Introduction To IPv6 Programming C Java PHP Perl
Introduction To IPv6 Programming C Java PHP Perl
Rino Nucara
GARR
rino.nucara@garr.it
EuChinaGRID IPv6 Tutorial
Rome, January 16th, 2008
Version 1.3
IPv4/IPv6 Interoperability
Bibliography
IPv6
IPv6 X X IPv6
IPv6
client
IPv4/IPv6 IPv4 IPv4 IPv6 IPv6
In C
#include <net/if.h>
char *if_indextoname(unsigned int ifindex, char *ifname);
#include <net/if.h>
struct if_nameindex *if_nameindex(void);
- a fourth function to return the dynamic memory allocated by the
previous functions.
#include <net/if.h>
void if_freenameindex(struct if_nameindex *ptr);
int i;
struct if_nameindex *ifs = if_nameindex();
if (ifs == NULL) { perror("could not run if_nameindex");return 1;}
if_freenameindex(ifs);
#define AF_INET6 10
#define PF_INET6 AF_INET6
IPv4
struct sockaddr_in
struct sockaddr
IPv6
struct sockaddr_in6
IPv4/IPv6/
struct sockaddr_storage
struct sockaddr_in {
sa_family_t sin_family; // Address family (2 bytes)
in_port_t sin_port; // Port number (2 bytes)
struct in_addr sin_addr; // Internet address (4 bytes)
char sin_zero[8]; // Empty (for padding) (8 bytes)
}
sockaddr_in is a parallel structure to deal with struct sockaddr for IPv4 addresses.
sin_port contains the port number and must be in Network Byte Order.
sin_family corresponds to sa_family (in a sockaddr structure) and contains the type of
address family (AF_INET for IPv4). As sin_port also sin_family must be in Network Byte
Order.
struct sockaddr_in {
sa_family_t sin_family; // Address family (2 bytes)
in_port_t sin_port; // Port number (2 bytes)
struct in_addr sin_addr; // Internet address (4 bytes)
char sin_zero[8]; // Empty (for padding) (8 bytes)
}
/* fill in addrIPv4{} */
RFC 3493 did not define the usage of the sin6_scope_id field because at the
time there was some debate about how to use that field.
The intent was to publish a separate specification to define its usage, but that
has
27 not happened. Rino Nucara - GARR IPv6 Tutorial
Address Data Structure:Sockaddr_in6 (sin6_scope_id)
To communicate with node A or node C, node B has to disambiguate
between them with a link-local address you need to specify the scope
identification.
ether0 ether1
fe80::1 fe80::1
The 4.4BSD release includes a small, but incompatible change to the socket interface.
The "sa_family" field of the sockaddr data structure was changed from a 16-bit value
to an 8-bit value, and the space saved used to hold a length field, named "sa_len".
The sockaddr_in6 data structure given in the previous section cannot be correctly
casted into the newer sockaddr data structure.
For this reason, the following alternative IPv6 address data structure is provided to be
used on systems based on 4.4BSD. It is defined as a result of including the
<netinet/in.h> header.
29 Rino Nucara - GARR IPv6 Tutorial
Address Data Structure: Sockaddr_in6 in BSD
For dealing this incompatible difference should be userfull to use Preprocessor
Directive:
[]
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
#ifdef __BSD__
sin6.sin6_len = sizeof(sin6);
#endif
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(5002);
[]
Padding
140
120
100
80
60
40
20
...
0
s.a. s.a.6 s.a. s.
In this code, the memset() operation will overwrite the memory region
immediately following the space that was allocated for the sockaddr{} structure.
It is therefore important to use a new address structure: sockaddr_storage{}
as a socket address placeholder throughout the code in order to avoid
introducing this kind of programming bug.
IPv6:
struct sockaddr_in6 addr;
socklen_t addrlen = sizeof(addr);
//fill addr structure using an IPv6 address
//before calling socket function
bind(sockfd,(struct sockaddr *)&addr, addrlen);
IPv6:
struct sockaddr_in6 addr;
socklen_t addrlen = sizeof(addr);
accept(sockfd,(struct sockaddr *)&addr, &addrlen);
// addr structure contains an IPv6 address
2 #include <netinet/in.h>.
#define IN6ADDR_ANY_INIT {{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
2 <netinet/in.h>
#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}}
1 #include <netinet/in.h>:
extern const struct in6_addr in6addr_any;
For example, to bind a socket to port number 23, but let the system select the
source address, an application could use the following code:
2 #include <netinet/in.h>.
#define IN6ADDR_ANY_INIT {{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
Note that this constant can be used ONLY at declaration time. It can not be
used to assign a previously declared in6_addr structure. For example, the
following code will not work:
/* This is the WRONG way to assign an unspecified address */
struct sockaddr_in6 sin6;
. . .
sin6.sin6_addr = IN6ADDR_ANY_INIT; /* will NOT compile */
1
<netinet/in.h>
extern const struct in6_addr in6addr_loopback;
2 <netinet/in.h>
#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}}
IPV6_UNICAST_HOPS
IPV6_MULTICAST_IF
IPV6_MULTICAST_HOPS
IPV6_MULTICAST_LOOP
IPV6_JOIN_GROUP
IPV6_LEAVE_GROUP
IPV6_V6ONLY
All of these new options are at the IPPROTO_IPV6 level (specifies the code
in the system to interpret the option).
The declaration for IPPROTO_IPV6 is obtained by including the header
<netinet/in.h>.
int hoplimit;
socklen_t len = sizeof(hoplimit);
if (
getsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
(char *) &hoplimit, &len)
== -1) perror("getsockopt IPV6_UNICAST_HOPS");
else
printf("Using %d for hop limit.\n", hoplimit);
int on = 1;
if(setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(char *)&on,sizeof(on))==-1)
perror("setsockopt IPV6_V6ONLY");
else
printf("IPV6_V6ONLY set\n");
An example use of this option is to allow two versions of the same server
process to run on the same port, one providing service over IPv6, the other
providing the same service over IPv4 (separated Stack).
memset(&sin6,0,sizeof(sin6));
sin6.sin6_family=AF_INET6; sin6.sin6_len=sizeof(sin6);
sin6.sin6_port=htons(5001);
s0=socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);
on=1; setsockopt=(s0,SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on));
#ifdef USE_IPV6_V6ONLY
on=1;
setsockopt(s0,IPPROTO_IPV6, IPV6_V6ONLY,&on,sizeof(on));
#endif
Using USE_IPV6_V6ONLY
telnet ::1 5001 Accept a connection from ::1
Trying 127.0.0.1
telnet: connection to address 127.0.0.1: Connection refused
CLIENT SERVER
IPv4 connection
$ telnet 127.0.0.1 5002 accept a connection from 127.0.0.1
SEPARATED STACK
CLIENT SERVER
For the most curious, Ive put a full code example here:
http://www.nucara.it/ipv6/
We will see at 2 pm
Old address conversion functions ( working only with IPv4 ) have been
replaced by new IPv6 compatible ones:
NEW
#include <arpa/inet.h>
int inet_pton(int family, const char *src, void *dst);
const char *inet_ntop(int family, const void *src, char *dst,
size_t cnt);
2001:db8::1234 In6_addr={0x20,0x01,0x0
d,0xb8,,0x12,0x34}
inet_ntop( )
in6_addr{}
128-bit binary inet_ntop(AF_INET6)
IPv4-mapped or x:x:x:x:x:x:a.b.c.d
IPv4-compatible inet_pton(AF_INET6)
IPv6 address
in6_addr{} inet_ntop(AF_INET6)
128-bit binary x:x:x:x:x:x:x:x
IPv6 address inet_pton(AF_INET6)
memset(&addr, 0, sizeof(addr));
#include <netdb.h>
struct hostent *gethostbyname(const char *name) DEPRECATED
#include <netdb.h>
#include <sys/socket.h> DEPRECATED
struct hostent *gethostbyname2(const char *name, int af)
#include <netdb.h>
#include <sys/socket.h>
int getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
#include <netdb.h>
#include <sys/socket.h>
AI_NUMERICHOST
specifies that nodename is a numeric host address string. Otherwise, an
[EAI_NONAME] error is returned. This flag shall prevent any type of name
resolution service (for example, the DNS) from being invoked.
AI_NUMERICSERV
specifies that servname is a numeric port string. Otherwise, an
[EAI_NONAME] error shall be returned. This flag shall prevent any type of
name resolution service (for example, NIS+) from being invoked.
AI_V4MAPPED
if no IPv6 addresses are matched, IPv4-mapped IPv6 addresses for IPv4
addresses that match nodename shall be returned. This flag is applicable
only when ai_family is AF_INET6 in the hints structure.
AI_ALL
If this flag is set along with AI_V4MAPPED when looking up IPv6 addresses
the function will return all IPv6 addresses as well as all IPv4 addresses. The
latter mapped to IPv6 format.
AI_ADDRCONFIG
Only addresses whose family is supported by the system will be returned:
IPv4 addresses shall be returned only if an IPv4 address is configured on the
local system, and IPv6 addresses shall be returned only if an IPv6 address is
configured on the local system. The loopback address is not considered for
this case as valid as a configured address.
The information returned in the addrinfo structures is ready for socket calls
and ready to use in the connect, sendto (for client) or bind (for server)
function.
ai_addr is a pointer to a socket address structure.
ai_addrlen is the length of this socket address structure.
ai_canonname member of the first returned structure points to the
canonical name of the host (if AI_CANONNAME flag is set in hints structure).
error=getaddrinfo("www.kame.net","http",&hints,&res0);
if(error)
{
fprintf(stderr,"error: %s\n",gai_strerror(error));
exit(1);
}
resave = res;
while (res) {
sockfd = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if (!(sockfd < 0))
break;
res = res->ai_next;
}
freeaddrinfo(ressave);
#include <sys/socket.h>
#include <netdb.h>
#include <netdb.h>
NI_MAXHOST //=1025 maximum size of returned host string
NI_MAXSERV //=32 maximum size of returned service string
[]
If the flag bit NI_NAMEREQD is set, an error shall be returned if the
host's name cannot be located.
the flag bit NI_NUMERICSERV is set, the numeric form of the service
address shall be returned (for example, its port number) instead of its
name, under all circumstances.
If the flag bit NI_DGRAM is set, this indicates that the service is a
datagram service (SOCK_DGRAM). The default behavior shall assume
that the service is a stream service (SOCK_STREAM).
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
error=getaddrinfo("www.kame.net","http",&hints,&res0);
[]
s=-1;
for(res=res0; res; res=res->ai_next){
s=socket(res->ai_family, res->ai_socktype,res->ai_protocol);
if(s<0) continue;
if(connect(s,res->ai_addr,res->ai_addrlen)<0){
close(s); s=-1; continue;}
break; // we got one!
}
if(s<0){fprintf(stderr,"No addresses are reachable");exit(1);}
freeaddrinfo(res0);
}
#include <netinet/in.h>
In JAVA
try {
serverSock = new ServerSocket(5000);
cs = serverSock.accept();
BufferedOutputStream b = new
BufferedOutputStream(cs.getOutputStream());
PrintStream os = new PrintStream(b,false);
os.println(hallo!); os.println("Stop");
cs.close();
os.close();
}catch (Exception e) {[...]}
try {
s = new Socket("localhost", 5000);
is = new DataInputStream(s.getInputStream());
String line;
while( (line=is.readLine())!=null ) {
System.out.println("received: " + line);
if (line.equals("Stop")) break;
}
is.close();
s.close();
}catch (IOException e) { [] }
InetAddress
Inet4Address Inet6Address
Returns the raw IP address of this InetAddress object. The result is in network
byte order: the highest order byte of the address is in getAddress()[0].
InetAddress addr=InetAddress.getLocalHost();
byte[] b=addr.getAddress();
for(int i: b){System.out.print(i+" ");} Output:
127 0 0 1
Given the name of a host, returns an array of its IP addresses, based on the
configured name service on the system.
System.out.print(
InetAddress.getByName("193.206.158.2").getHostName()
);
output:
lx1.dir.garr.it
String addr=ia.getHostAddress();
System.out.println(addr); //print IP ADDRESS
InetAddress[ ] alladr=ia.getAllByName("www.kame.net");
for(int i=0;i<alladr.length;i++) {
System.out.println( alladr[i] ); }
Output:
www.kame.net/203.178.141.194
www.kame.net/2001:200:0:8002:203:47ff:fea5:3085
Inet6Address.isIPv4CompatibleAddress()
Net. Int. : lo
-------------------------
CanonicalHostName: ip6-localhost
addr type: IPv6 IP: 0:0:0:0:0:0:0:1%1
Loopback? True SiteLocal? False LinkLocal? false
-------------------------
CanonicalHostName: localhost
addr type: IPv4 IP: 127.0.0.1
Loopback? True SiteLocal? False LinkLocal? false
108 Rino Nucara - GARR IPv6 Tutorial
IPv6 Networking Properties: preferIPv4Stack
java.net.preferIPv4Stack (default: false)
Net. Int. : lo
-------------------------
CanonicalHostName: ip6-localhost
IP: 0:0:0:0:0:0:0:1%1
-------------------------
CanonicalHostName: localhost
IP: 127.0.0.1
Net. Int. : lo
-------------------------
CanonicalHostName: localhost
IP: 127.0.0.1
System.setProperty("java.net.preferIPv4Stack","true");
System.setProperty("java.net.preferIPv6Addresses","true");
InetAddress ia=InetAddress.getByName("www.kame.net");
String ss=ia.getHostAddress();
System.out.println(ss);//print 2001:200:0:8002:203:47ff:fea5:3085
This method allows the application to express its own preferences to tune the
performance characteristics of this socket. Performance preferences are
described by three integers whose values indicate the relative importance of
short connection time, low latency, and high bandwidth. With this method, the
network oriented notion of Quality of Service (QoS) is introduced. Any
application can set its preferences to adapt its network traffic and provide the
best QoS.
connectionTime: An int expressing the relative importance of a short
connection time.
latency: An int expressing the relative importance of low latency.
bandwidth: An int expressing the relative importance of high bandwidth.
If the application prefers short connection time over both low latency and high bandwidth, for example,
then it could invoke this method with the values (1, 0, 0).
If the application prefers high bandwidth above low latency, and low latency above short connection
time, then it could invoke this method with the values (0, 1, 2).
115 Rino Nucara - GARR IPv6 Tutorial
Bibliography
In PERL
use Socket
Use Socket6
This function converts string format IPv4/IPv6 addresses to binary format, the
FAMILY argument specify the type of address (AF_INET or AF_INET6).
example
$a=inet_ntop(AF_INET6,inet_pton(AF_INET6,"::1"));
print $a; //print ::1
example
$lh6=inet_pton(AF_INET6,"::1");
$p_saddr6=pack_sockaddr_in6(80,$lh6);
($port,$host) = unpack_sockaddr_in6($p_saddr6);
print inet_ntop(AF_INET6,$host); //print ::1
print $port; //print 80
unpack_sockaddr_in6_all (NAME)
This function unpacks a sockaddr_in6 structure to an array of four element:
- The port number
- Flow informations
- IPv6 network address (16-byte format)
- The scope of the address
This function converts node names to addresses and service names to port
numbers. At least one of NODENAME and SERVICENAME must have a true
value. If the lookup is successful this function returns an array of information
blocks. Each information block consists of five elements: address family,
socket type, protocol, address and canonical name if specified.
The arguments in squared brackets are optional.
This function returns a node or a service name. The optional attribute FLAGS
controls what kind of lookup is performed.
if ($family != -1) {
print STDERR "connected to $host port port $port\n";
} else {
die "connect attempt failed\n";
}
Example output
()=getnameinfo($saddr,NI_NUMERICHOST|NI_NUMERICSERV);
print STDERR "Trying to connect to $host port $port";
OUTPUT:
Trying to connect to 2001:200:0:8002:203:47ff:fea5:3085 port 80
()=getnameinfo($saddr,0);
print STDERR "Trying to connect to $host port $port";
OUTPUT:
Trying to connect to orange.kame.net port www
gai_strerror (ERROR_NUMBER)
in6addr_any
in6add_loopback
This function returns the 16-octet loopback address.
This function takes either a node name or an IP address string and performs a
lookup on that name (or conversion of the string). It returns a list of five
elements: the canonical host name, the address family, the length in octets of
the IP addresses returned, a reference to a list of IP address structures, and a
reference to a list of aliases for the host name. This function was deprecated
in RFC3493. The getnameinfo function should be used instead.
In PHP
This function converts a human readable IPv4 or IPv6 address (if PHP was
built with IPv6 support enabled) into an address family appropriate 32bit or
128bit binary structure.
Note: This function is not implemented on Windows platforms.
$in_addr = inet_pton('127.0.0.1');
$in6_addr = inet_pton('::1');
This function converts a 32bit IPv4, or 128bit IPv6 address (if PHP was built
with IPv6 support enabled) into an address family appropriate string
representation. Returns FALSE on failure.
Note: This function is not implemented on Windows platforms.
//www.kame.net
$ip='[2001:200::8002:203:47ff:fea5:3085]';
kame-anime-small.gif
137 Rino Nucara - GARR IPv6 Tutorial
gethostbyname
string gethostbyname ( string $hostname )
Pear Net_IPv6 Provides function to work with the 'Internet Protocol v6.
Net_IPv6::checkIPv6() -- Validation of IPv6 addresses
Net_IPv6::compress() -- compress an IPv6 address
Net_IPv6::uncompress() -- Uncompresses an IPv6 address
Net_IPv6::getAddressType() -- Returns the type of an IP address
Net_IPv6::getNetmask() -- Calculates the network prefix
Net_IPv6::isInNetmask() -- Checks if an IP is in a specific address space
Net_IPv6::removeNetmaskSpec() -- Removes the Netmask length
specification
Net_IPv6::splitV64() -- splits an IPv6 address in it IPv6 and IPv4 part
Returns the type of an IP address. RFC 2460, Section 2.3 describes several
types of addresses in the IPv6 addresse space. This methods tries to find the
type of address for the given IP.
Return the addresstype (int). the type can be one of this constants:
NET_IPV6_MULTICAST
NET_IPV6_UNICAST_PROVIDER
NET_IPV6_LOCAL_LINK
NET_IPV6_LOCAL_SITE
NET_IPV6_UNKNOWN_TYPE
NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC
NET_IPV6_RESERVED_IPX
NET_IPV6_RESERVED
NET_IPV6_RESERVED_NSAP
NET_IPV6_UNASSIGNED
Splits an IPv6 address into the IPv6 and a possible IPv4-formated part. RFC
2373 allows you to note the last two parts of an IPv6 address in the IPv4
address format.
Parameter
string $ip - the IP address to split
Return value
array - key [0] contains the IPv6 part
key [1] the IPv4 formated part
This function can be called statically.