3 IP addresses

IP Addresses, struct and Data Mungling

Table of Contents

Address

Subnets

It's sometimes convenient to declare that "this first part of this IP address up through this bit is the network portion of the IP address, and the remainder is the host portion.What that actually means is in 192.0.2.12 192.0.2.0(first three bytes) is the network address and 12 is the host1.\\ The network portion of the IP address(192.0.2.0) is described by something called the netmask2,which you bitwise-AND with the IP address to get the network number(network address without host) out of it. Netork Number = netmask bitwise-AND IP address. IP is 192.0.2.12, then your network is 192.0.2.12 AND 255.255.255.0 which gives 192.0.2.0.\\ No ok basically 255.255.255.0 means class c addresses, 255.255.255.0 means class b. A subnet divides network range into local addresses. This video explains it much better.

Port Numbers

It is a 16-bit number that's like the local address for the connection. It is used to differentiate between the services(not just web related). And to see all the assigned poets simply go to your computer's /etc/services.

byte order

if you want to represent the two-byte hex number, say b34f, you'll store it in two sequential bytes b3 followed by 4f. This number, stored with the big end first, is called Big-Endian.Also called Network Byte order(because thats the type easier to deal with)\\

Anything with an Intel or Intel-compatible processor, store the bytes reversed, so b34f would be stored in memory as the sequential bytes 4f followed by b3. This storage method is called Little-Endian.

Our computer stores numbers in host byte order. Now how can we convert little-endian to network byte order? A function will do that for us(or leave as it is if its in big-endian). And with numbers, there are two types, short(2 bytes) and long(4 bytes).  To convert short we use =htons=(read "Host to Network short"). We can use every sensible combination of 'h','h','l','s'.

functiondescription
htons()host to network short
htonl()host to network long
ntohs()network to host short
ntohl()network to host long

Apparently is for 32bit only.

=struct=s

As previously mentioned a socket descriptor is of the type int.

struct addrinfo

is used to prep the socket address structures for subsequent use. It is also used host name lookups and service name lookups.

struct addrinfo {
    int              ai_flags;     // AI_PASSIVE, AI_CANONNAME, etc.
    int              ai_family;    // AF_INET, AF_INET6, AF_UNSPEC
    int              ai_socktype;  // SOCK_STREAM, SOCK_DGRAM
    int              ai_protocol;  // use 0 for "any"
    size_t           ai_addrlen;   // size of ai_addr in bytes
    struct sockaddr *ai_addr;      // struct sockaddr_in or _in6
    char            *ai_canonname; // full canonical hostname

    struct addrinfo *ai_next;      // linked list, next node
};

You'll load this struct up a bit, and then call getaddrinfo(). It'll return a pointer to a new linked list of these structures filled out with all the goodies you need.

We can force it to use IPv4 or IPV6 using ai_family or leave as it is for machine to decide. We can also see that ai_addr is a pointer to a stuct sockaddr. A call to getaddrinfo() to fill out your struct addrinfo for you is all you'll need3. Some structs are IPv4, some are IPv6, and some are both.

struct sockaddr

Anyway, the struct sockaddr holds socket address information for types of sockets.

struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
}; 

Here sa_family can be a variety of things, but it will be mostly IPv4(AFINET) or IPv6(INET6) in our discussion. sa_data contains a destination address and port number of the socket.

struct sockaddr_in

To deal with IPv4 we have stuct sockaddr_in (in for internet). We can cast sockaddr to sockaddr_in and vice-Versa to use it with connect().

// (IPv4 only--see struct sockaddr_in6 for IPv6)

struct sockaddr_in {
    short int          sin_family;  // Address family, AF_INET
    unsigned short int sin_port;    // Port number
    struct in_addr     sin_addr;    // Internet address
    unsigned char      sin_zero[8]; // Same size as struct sockaddr
};

sin_zero shoudl be set to all zeros with the function memset() (it copies char in a char array), it is inculded to pad the structure to the length of a struct sockaddr.\\ sin_family corresponds to the sa_family in sockaddr. And at last, sin_port should be in Network Byte Order.

struct in_addr

// (IPv4 only--see struct in6_addr for IPv6)

// Internet address (a structure for historical reasons)
struct in_addr {
    uint32_t s_addr; // that's a 32-bit int (4 bytes)
};

It used to be a union long time ago. If ina is of type sockaddr_in, then ina.sin_addr.s_addr references the 4-byte IP address in network byte order.\\ Same is true for IPv6 but with

struct sockaddr_in6 and struct in6_addr

// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4)

struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

struct in6_addr {
    unsigned char   s6_addr[16];   // IPv6 address
};

Above one for IPv6, but what if we don't want to care about the type? we use. sockaddr_storage

struct sockaddr_storage {
    sa_family_t  ss_family;     // address family

    // all this is padding, implementation specific, ignore it:
    char      __ss_pad1[_SS_PAD1SIZE];
    int64_t   __ss_align;
    char      __ss_pad2[_SS_PAD2SIZE];
};

It is big enough to hold both IPv4 and IPv6 and can cast in any one. Here sa_family will provide us with family type, then we can use to cast.

IP Addresses, Part Deux

We will talk about a bunch of functions to manipulate IP addresses. OK? lets start. Suppose we want to store 139.120.12.57 into struct sockaddr_in ina, we will use =inetpton()=(presentation to network or printable to network, whichever one you wanna choose). It takes 3 parameters, first type of address(AF_INET or AF_INET6), second the input string and third, where you want to store the address.

struct sockaddr_in sa; // IPv4
struct sockaddr_in6 sa6; // IPv6

inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6

inet_pton returns -1 on error and 0 if address is messed up. And to convert binary to string we can use inet_ntop() function.

// IPv4:

char ip4[INET_ADDRSTRLEN];  // space to hold the IPv4 string
struct sockaddr_in sa;      // pretend this is loaded with something

inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);

printf("The IPv4 address is: %s\n", ip4);

// IPv6:

char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
struct sockaddr_in6 sa6;    // pretend this is loaded with something

inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);

printf("The address is: %s\n", ip6);

These only work with numeric addresses and not with DNS lookups on a hostname.

Private networks

To hide network from external network(for security and stuff) firewall translates 'internal' IP address to 'external' using /Network Address Translation/(NAT for short).

Footnotes:

1

There are(were, ancient stuff) multiple classes of subnets, A class means first byte is for adress and reamining three for the host. B for two for network part and two for host and one for host in C type.

2

Netmask looks like 255.255.255.0

3

Before stuct addrinfo was a thing, we used to pack all the stuff mentioned manually