How to read virtual IP in linux using golang/net package - linux

I am trying to read a particular interface and all the virtual IP in that interface.
Here is and example of the linux ifconfig -a | grep -A eth0
ifconfig -a | grep -A2 eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 100.180.89.148 netmask 255.255.255.224 broadcast 100.180.89.140
inct6 fe80::ac16:2dff:fead:a321 prefixlen 64 scopeid 0x20<link>
--
eth0:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 100.180.89.150 netmask 255.255.255.255 broadcast 100.180.89.150
ether cc:16:2d:ad:a3:20 txqueuelen 1000 (Ethernet)
--
eth0:2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 100.180.89.151 netmask 255.255.255.255 broadcast 100.180.89.151
ether ac:16:2d:ad:a3:20 txqueuelen 1000 (Ethernet)
--
eth0:3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 100.180.89.152 netmask 255.255.255.255 broadcast 100.180.89.152
ether ac:16:2d:ad:a3:20 txqueuelen 1000 (Ethernet)
I tried like this in go code:
// nwkIfName = eth0
func networkInterfaces(nwkIfName string) ([]Interfaces, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("failed to get network interfaces: %w", err)
}
for _, nwIf := range ifaces {
fmt.Println(nwIf.Name)
if nwIf.Name == nwkIfName {
fmt.Println(nwIf.Addrs())
}
}
return nil, nil
}
Output:
[100.180.89.148/27 100.180.89.150/32 100.180.89.151/32 100.180.89.152/32 fe80::ae16:2dff:fead:a320/64] <nil>
How can I read the IP address of eth0:2 ?
Thanks James

Call Interface.Addrs() to get the interface's addresses, and type-assert *net.IPNet from the addresses.
Use its IPNet.IP field to get just the IP address (of type net.IP), and its IP.To4() method if you need an IPv4 address.
for _, nwIf := range ifaces {
fmt.Println(nwIf.Name)
if nwIf.Name == nwkIfName {
fmt.Println(nwIf.Addrs())
addrs, err := nwIf.Addrs()
if err != nil {
return nil, fmt.Errorf(
"failed to get addresses of interface: %s, err: %w",
nwIf.Name, err,
)
}
for _, addr := range addrs {
if ipNet, ok := addr.(*net.IPNet); ok {
fmt.Println("\tIP:", ipNet.IP)
} else {
fmt.Println("\tnot IPNet:", addr)
}
}
}
}

Related

bind(): "Cannot assign request address"

I am aware of bind: cannot assign requested address and Cannot assign requested address - possible causes?, I have not been able to derive a solution from these.
I am trying to create a TCP stream (specifically here a std::net::TcpListener) directly with libc. I am encountering the error Cannot assign requested address and error code: 99 when running my code.
The exact output being:
error message: error code: : Cannot assign requested address
thread 'main' panicked at 'error code: 99', src/main.rs:43:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
My code (playground):
use libc; // 0.2.136
use std::mem::{size_of, transmute};
fn main() {
// Create socket
let socket_fd = unsafe {
let socket = libc::socket(libc::AF_INET6, libc::SOCK_STREAM | libc::SOCK_NONBLOCK, 0);
assert_ne!(socket, -1);
let optval = 1i32;
let res = libc::setsockopt(
socket,
libc::SOL_SOCKET,
libc::SO_REUSEPORT,
(&optval as *const i32).cast(),
4,
);
assert_eq!(res, 0);
socket
};
// Bind socket
// decimal 127.0.0.1 -> hexadecimal 007f.0000.0000.0001
let sin6_addr = unsafe { transmute::<_, libc::in6_addr>(*b"007f000000000001") };
let socket_address = libc::sockaddr_in6 {
sin6_family: libc::AF_INET6 as u16,
sin6_port: 8080,
sin6_flowinfo: u32::default(),
sin6_addr,
sin6_scope_id: u32::default(),
};
let socket_address_length = size_of::<libc::sockaddr_in6>() as u32;
unsafe {
let res = libc::bind(
socket_fd,
(&socket_address as *const libc::sockaddr_in6).cast(),
socket_address_length,
);
if res == -1 {
let err = errno();
print_error("error message: ");
panic!("error code: {err}");
}
}
assert_eq!(unsafe { libc::close(socket_fd) },0);
}
fn print_error(s: &str) {
unsafe {
libc::perror(s.as_ptr().cast());
}
}
fn errno() -> i32 {
unsafe { *libc::__errno_location() }
}
I set the option SO_REUSEPORT here as I need to create a stream that multiple processes can listen to.
https://lwn.net/Articles/542629/:
The basic concept of SO_REUSEPORT is simple enough. Multiple servers (processes or threads) can bind to the same port
The port does not appear to be in use:
jonathan#jonathan-pc:~$ sudo lsof -i -P -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd-r 793 systemd-resolve 13u IPv4 19452 0t0 UDP 127.0.0.53:53
systemd-r 793 systemd-resolve 14u IPv4 19453 0t0 TCP 127.0.0.53:53 (LISTEN)
avahi-dae 855 avahi 12u IPv4 31377 0t0 UDP *:5353
avahi-dae 855 avahi 13u IPv6 31378 0t0 UDP *:5353
avahi-dae 855 avahi 14u IPv4 31379 0t0 UDP *:49594
avahi-dae 855 avahi 15u IPv6 31380 0t0 UDP *:58397
NetworkMa 859 root 36u IPv4 36212 0t0 UDP 192.168.0.22:68->192.168.0.1:67
NetworkMa 859 root 37u IPv4 110801 0t0 UDP 192.168.0.17:68->192.168.0.1:67
tor 1038 debian-tor 6u IPv4 31407 0t0 TCP 127.0.0.1:9050 (LISTEN)
rust-anal 4117 jonathan 46u IPv4 33176 0t0 UDP 127.0.0.1:35972->127.0.0.53:53
rust-anal 4189 jonathan 46u IPv4 33176 0t0 UDP 127.0.0.1:35972->127.0.0.53:53
firefox 4297 jonathan 3u IPv4 112786 0t0 TCP 192.168.0.22:46702->151.101.1.69:443 (ESTABLISHED)
firefox 4297 jonathan 29u IPv4 100032 0t0 TCP 192.168.0.22:55828->34.120.208.123:443 (ESTABLISHED)
firefox 4297 jonathan 56u IPv4 115182 0t0 TCP 192.168.0.22:50798->52.51.190.37:443 (ESTABLISHED)
firefox 4297 jonathan 75u IPv4 95741 0t0 TCP 192.168.0.22:48466->142.250.200.10:443 (ESTABLISHED)
firefox 4297 jonathan 81u IPv4 67879 0t0 TCP 192.168.0.22:55638->34.214.17.205:443 (ESTABLISHED)
firefox 4297 jonathan 116u IPv4 111739 0t0 TCP 192.168.0.22:37986->172.217.169.68:443 (ESTABLISHED)
firefox 4297 jonathan 121u IPv4 95751 0t0 TCP 192.168.0.22:46054->198.252.206.25:443 (ESTABLISHED)
firefox 4297 jonathan 129u IPv4 102073 0t0 TCP 192.168.0.22:51478->34.120.237.76:443 (ESTABLISHED)
firefox 4297 jonathan 136u IPv4 96742 0t0 TCP 192.168.0.22:36606->34.120.115.102:443 (ESTABLISHED)
firefox 4297 jonathan 139u IPv4 97943 0t0 TCP 192.168.0.22:36626->172.217.169.68:443 (ESTABLISHED)
firefox 4297 jonathan 144u IPv4 99520 0t0 TCP 192.168.0.22:49264->198.252.206.25:443 (ESTABLISHED)
firefox 4297 jonathan 157u IPv4 104859 0t0 TCP 192.168.0.22:58042->93.184.220.29:80 (ESTABLISHED)
jonathan#jonathan-pc:~$
You are transmuting b"007f000000000001" into a libc::in6_addr. But I don't thing that is the proper thing to do.
Looking at the man page, that struct is:
struct in6_addr {
uint8_t s6_addr[16];
};
That is, just 16 bytes, the proper thing for an IPv6. But your bytes are actually the ASCII values of that string: 30303766..., that while technically an IPv6 address, it is not a local one of yours so you cannot bind to it.
Moreover, in IPv6 the proper localhost address is ::1, not 127.0.0.1. That is 15 zeros followed by a single one.
If you want to bind to the IPv6 localhost by using a transmute that would be:
let sin6_addr = unsafe { transmute::<_, libc::in6_addr>([0_u8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]) };
Or if you insist on using a literal string (why?):
let sin6_addr = unsafe { transmute::<_, libc::in6_addr>(*b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01") };

nodejs dgram udp socket listen on specific interface

I'm currently implementing a legacy proprietary udp protocol with nodejs. It's necessary to know from which network interface the packages were coming from.
I tried to bind two sockets to their network addresses. Any ideas what I'm doing wrong here?
> ifconfig
en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=400<CHANNEL_IO>
ether 3c:22:fb:4b:fc:31
inet6 fe80::1c0f:d365:a86d:be5d%en0 prefixlen 64 secured scopeid 0x6
inet 192.168.178.70 netmask 0xffffff00 broadcast 192.168.178.255
inet6 2001:16b8:2ef3:4200:10d4:27f8:4945:c138 prefixlen 64 autoconf secured
inet6 2001:16b8:2ef3:4200:d919:b3b1:6220:ca12 prefixlen 64 autoconf temporary
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
en8: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=6407<RXCSUM,TXCSUM,VLAN_MTU,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether 9c:eb:e8:85:92:6c
inet6 fe80::10b6:fa35:b1ee:ca68%en8 prefixlen 64 secured scopeid 0x1d
inet 192.168.2.10 netmask 0xffffff00 broadcast 192.168.2.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (100baseTX <full-duplex>)
status: active
import * as dgram from 'dgram';
const socket1 = dgram.createSocket('udp4');
const socket2 = dgram.createSocket('udp4');
socket1.on('error', (error)=>{
console.log('socket1 error:', JSON.stringify(error, null, 4));
})
socket2.on('error', (error)=>{
console.log('socket2 error:', JSON.stringify(error, null, 4));
})
socket1.on('message', (message)=>{
console.log('socket1 message:', JSON.stringify(message, null, 4));
})
socket2.on('message', (message)=>{
console.log('socket2 message:', JSON.stringify(message, null, 4));
})
socket1.bind({
port:2000,
address: '192.168.2.0',
exclusive:false,
}, ()=>{
socket1.setBoradcast(true)
});
socket2.bind({
port:2000,
address: '192.168.178.0',
exclusive:false,
}, ()=>{
socket2.setBoradcast(true)
});
Produces the following output:
socket1 error: {
"errno": "EADDRNOTAVAIL",
"code": "EADDRNOTAVAIL",
"syscall": "bind",
"address": "192.168.2.0",
"port": 2000
}
socket2 error: {
"errno": "EADDRNOTAVAIL",
"code": "EADDRNOTAVAIL",
"syscall": "bind",
"address": "192.168.178.0",
"port": 2000
}
Edit 1:
Thanks to answer of #Steffen Ullrich I'm now able to bind the sockets.
But now I cannot receive broadcast messages on these sockets on macos (It works on windows). Any chance to receive those broadcasts also on macos?
You are using the wrong addresses:
inet 192.168.178.70 netmask 0xffffff00 broadcast 192.168.178.255
^^^^
inet 192.168.2.10 netmask 0xffffff00 broadcast 192.168.2.255
^^^^
vs.
address: '192.168.2.0',
^^^
address: '192.168.178.0',
^^^

How to find/grep ethernet interface (en) from inet ip in Mac shell script

I want to grep or need result which ethernet interface "en" is getting inet ip.
In below ifconfig in terminal result en6 is getting inet 192.188.10.111 so the result should be en6.
example: If en2 oren5 or any en XxX is getting inet IP id should show the ethernet interface enno.
It should not show lo0 loopback inet 127.0.0.1
MY_MAC:~ SKULL$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=3<RXCSUM,TXCSUM>
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=1<PERFORMNUD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
ether 83:c1:9y:z0:g9:99
nd6 options=1<PERFORMNUD>
media: autoselect (<unknown type>)
status: inactive
en1: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=60<TSO4,TSO6>
ether 99:85:40:69:05:z0
media: autoselect <full-duplex>
status: inactive
en2: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=60<TSO4,TSO6>
ether 99:84:43:67:43:b6
media: autoselect <full-duplex>
status: inactive
p2p0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 2304
ether 09:k5:6m:s6:q1:78
media: autoselect
status: inactive
awdl0: flags=8902<BROADCAST,PROMISC,SIMPLEX,MULTICAST> mtu 1452
ether w1:6t:c3:w2:n4:78
nd6 options=1<PERFORMNUD>
media: autoselect
status: inactive
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=63<RXCSUM,TXCSUM,TSO4,TSO6>
ether 23:j5:12:43:43:67
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x2
member: en1 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 5 priority 0 path cost 0
member: en2 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 6 priority 0 path cost 0
nd6 options=1<PERFORMNUD>
media: <unknown type>
status: inactive
en6: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet6 fe80::2e0:4cff:fe36:550%en6 prefixlen 64 scopeid 0xb
inet 192.188.10.111 netmask 0xffffff00 broadcast 192.168.255.255
nd6 options=1<PERFORMNUD>
media: autoselect (100baseTX <full-duplex>)
status: active
Does this meet your needs?
#!/bin/bash
for interface in `ifconfig | grep -v "\t" | awk -F':' '{print $1}'`; do
if [ `ipconfig getifaddr $interface` ] ; then
echo $interface
fi
done

IPV6 Binding Failure Error: Cannot assign requested address

I have configured Ubuntu Linux system with the following interfaces & assigned IPV6 addresses as follows:
Eth0: Link encap:Ethernet HWaddr 00:50:56:8d:57:64
inet addr:192.168.254.10 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::250:56ff:fe8d:5764/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:74231424 errors:0 dropped:1 overruns:0 frame:0
TX packets:400372550 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:24514286488 (24.5 GB) TX bytes:115992171490 (115.9 GB)
Eth1: Link encap:Ethernet HWaddr 00:50:56:8d:7c:4c
inet addr:192.168.1.10 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::250:56ff:fe8d:7c4c/64 Scope:Link
inet6 addr: fc00:1234:1::10/120 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:434933479 errors:0 dropped:1 overruns:0 frame:0
TX packets:39666183 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:126065364448 (126.0 GB) TX bytes:14437801257 (14.4 GB)
Eth2: Link encap:Ethernet HWaddr 00:50:56:8d:56:14
inet addr:192.168.2.10 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fc00:1234:2::10/120 Scope:Global
inet6 addr: fe80::250:56ff:fe8d:5614/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:480068741 errors:0 dropped:0 overruns:0 frame:0
TX packets:34145702 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:146795537550 (146.7 GB) TX bytes:10045338657 (10.0 GB)
I wanted to do Socket programming using IPV6 sockets. The code snippet that I have written is as follows:
struct sockaddr_in6 sin
Ipv6_fdr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)
bzero(&sin, sizeof(sin));
sin.sin6_family = AF_INET6;
sin.sin6_port = htons(2152);
if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int))) < 0)
memcpy(&(sin.sin6_addr), "fc00:1234:1::10",sizeof(sin.sin6_addr));
if ((bind(sock, (struct sockaddr*)&sin, sizeof(sin)))< 0)
After successful compilation, I’m getting IPV6 bind failure Error with the following error number & name:
EADDRNOTAVAIL 99 /* Cannot assign requested address.
After certain number of attempts for IPV6 Binding it throws Segmentation Fault error.
It would be great if someone could help me on what mistake I’m doing here & why IPV6 binding is failing?
The problem in your code is the line:
memcpy(&(sin.sin6_addr), "fc00:1234:1::10",sizeof(sin.sin6_addr));
It is necessary to convert the human readable string to binary and store the binary form of address to sin6_addr like:
inet_pton (AF_INET6, "fc00:1234:1::10", sin.sin6_addr.s6_addr);

How to get scope of an IPv6 host?

I don't have much knowledge about the IPv6 protocol, so sorry if the question sounds stupid.
When I retrieve the list of all IPv6 addresses in my network, I get a field named scope, as shown below :
inet6 addr: 2001:470:1:82::11/64 Scope:Global
inet6 addr: 2001:470:1:82::10/64 Scope:Global
inet6 addr: 2001:470:1:82::13/64 Scope:Global
inet6 addr: fe80::21d:9ff:fe69:2c50/64 Scope:Link
inet6 addr: 2001:470:1:82::12/64 Scope:Global
inet6 addr: 2001:470:1:82::15/64 Scope:Global
inet6 addr: 2001:470:1:82::14/64 Scope:Global
inet6 addr: 2001:470:1:82::5/64 Scope:Global
inet6 addr: 2001:470:1:82::17/64 Scope:Global
inet6 addr: 2001:470:1:82::6/64 Scope:Global
inet6 addr: 2001:470:1:82::16/64 Scope:Global
inet6 addr: 2001:470:1:82::7/64 Scope:Global
inet6 addr: 2001:470:1:82::19/64 Scope:Global
inet6 addr: 2001:470:1:82::8/64 Scope:Global
inet6 addr: 2001:470:1:82::18/64 Scope:Global
inet6 addr: 2001:470:1:82::9/64 Scope:Global
inet6 addr: 2001:470:1:82::1b/64 Scope:Global
inet6 addr: 2001:470:1:82::a/64 Scope:Global
inet6 addr: 2001:470:1:82::1a/64 Scope:Global
inet6 addr: 2001:470:1:82::b/64 Scope:Global
inet6 addr: 2001:470:1:82::1d/64 Scope:Global
inet6 addr: 2001:470:1:82::c/64 Scope:Global
inet6 addr: 2001:470:1:82::1c/64 Scope:Global
inet6 addr: 2001:470:1:82::d/64 Scope:Global
inet6 addr: 2001:470:1:82::1f/64 Scope:Global
inet6 addr: 2001:470:1:82::e/64 Scope:Global
inet6 addr: 2001:470:1:82::1e/64 Scope:Global
inet6 addr: 2001:470:1:82::f/64 Scope:Global
inet6 addr: ::1/128 Scope:Host
In my application, I need to get those addresses for which the scope is 'Link'. I could have used a system call to ifconfig and then parsed the output to extract corresponding addresses. But the problem is, I'm using the call to getifaddrs(), which returns a linked list of structure ifaddr, given as :
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union {
struct sockaddr *ifu_broadaddr;
/* Broadcast address of interface */
struct sockaddr *ifu_dstaddr;
/* Point-to-point destination address */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};
The question is : how to get the addresses with 'Link' scope from this list ?
There are helper macros to assist:
struct sockaddr_in6 s6;
if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
puts ("link-local");
} else if (IN6_IS_ADDR_SITELOCAL(&s6.sin6_addr)) {
puts ("site-local");
} else if (IN6_IS_ADDR_V4MAPPED(&s6.sin6_addr)) {
puts ("v4mapped");
} else if (IN6_IS_ADDR_V4COMPAT(&s6.sin6_addr)) {
puts ("v4compat");
} else if (IN6_IS_ADDR_LOOPBACK(&s6.sin6_addr)) {
puts ("host");
} else if (IN6_IS_ADDR_UNSPECIFIED(&s6.sin6_addr)) {
puts ("unspecified");
} else {
puts ("global");
}
One way to do this would simply be to check whether the address falls within fe80::/10. The IPv6 address space is available from IANA, which details the possible scopes available.
I downloaded the source code to net-tools (the source package for ifconfig), and it looks like they parse /proc/net/if_inet6. (Comments are my own additions in the following code — also the below is extremely abridged and will most certainly not compile.)
/* some defines collected around the place: */
#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
#define IPV6_ADDR_LOOPBACK 0x0010U
#define IPV6_ADDR_LINKLOCAL 0x0020U
#define IPV6_ADDR_SITELOCAL 0x0040U
#define IPV6_ADDR_COMPATv4 0x0080U
int scope; /* among other stuff */
/* looks like here we parse the contents of /proc/net/if_inet6: */
if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
&if_idx, &plen, &scope, &dad_status, devname) != EOF) {
/* slightly later: */
printf(_(" Scope:"));
switch (scope) {
case 0:
printf(_("Global"));
break;
case IPV6_ADDR_LINKLOCAL:
printf(_("Link"));
break;
case IPV6_ADDR_SITELOCAL:
printf(_("Site"));
break;
case IPV6_ADDR_COMPATv4:
printf(_("Compat"));
break;
case IPV6_ADDR_LOOPBACK:
printf(_("Host"));
break;
default:
printf(_("Unknown"));
}
So let's have a look at what the above is parsing:
$ cat /proc/net/if_inet6
20010db8000008000000000000000001 03 40 00 00 eth0
fe800000000000000000000000004321 03 40 20 80 eth0
00000000000000000000000000000001 01 80 10 80 lo
So you can see the third column from the left (0x00 Global, 0x20 Link-Local, and 0x10 Loopback) is the scope. Using the above constants from the net-tools code you can work out what they mean. Further investigation would be required to determine a more authoritative source for such constants, and also whether parsing /proc/net/if_inet6 is your best option.
I don't think the scope is stored explicitly in that data structure. However, you can infer the scope from the IP address itself. See http://en.wikipedia.org/wiki/IPv6_address#Address_scopes

Resources