240 likes | 424 Views
ioctl Operations. Computer Network Programming. Use of ioctl(). It is the system interface to set and get attributes of devices, sockets, files, interfaces tables like routing table, arp table... The same operations can be performed by Use of special functions such as tcgetattr()
E N D
ioctl Operations Computer Network Programming
Use of ioctl() • It is the system interface to set and get attributes of • devices, sockets, files, • interfaces • tables like routing table, arp table... • The same operations can be performed by • Use of special functions such as tcgetattr() • Use of routing domain sockets (AF_ROUTE family) • Use of fcntl function
ioctl function() #include <unistd.h> int ioctl (int fd, int request, void *arg); • arg pointer type depends on the request. • Request can be divided into following categories: • - Socket operations • File operations • Interface operations • ARP cache operations • Routing table operations
Socket Operations • SIOCATMARK: integer • Return if the socket’s read pointer is currently on the out-of-band data • SIOCGPGRP: int • Return the process ID or the process group ID that is set to receive the SIGIO or SIGURG signal for this socket • SIOCSPGRP: int • Set either the process ID or process group ID to receive the SIGIO or SIGURG signal for this socket
File Operations • FIONBIO: integer • Clear or turn on the non-blocking flag for the socket. • FIOASYNC: integer • Clear or turn on the receipt of asynchronous I/O signals (SIGIO) for the socket. • FIONREAD: integer • Return the number of bytes currently available in the socket receive buffer. • FIOSETOWN; integer • Equivalent to SIOCSPGRP for a socket • FIOGETOWN: integer • Equivalent to SIOCGPGRP for a socket
Interface Configuration • It is possible to obtain information about all the network interfaces configured on the system • IP address, flags <BCAST, PTP, MCAST, ...>, Bcast address, Interface name, .... • It is possible to set the IP address, bcast address, dest address for ptp links, some flags for the interface
Interface Operations REQUEST Description Datatype ----------------------------------------------------------------------------------------- SIOCGIFCONF get list of all interfaces struct ifconf SIOCSIFADDR set interface address struct ifreq SIOCGIFADDR get interface address struct ifreq SIOCSIFFLAGS set interface flags struct ifreq SIOCGIFFLAGS get interface flags struct ifreq SIOCSIFDSTADDR set point-to-point address struct ifreq SIOCGIFDSTADDR get point-to-point address struct ifreq SIOCSIFBRADDR set broadcast address struct ifreq SIOCGIFBRADDR get broadcast address struct ifreq SIOCGIFNETMASK get subnet mask struct ifreq SIOCSIFNETMASK set subnet mask struct ifreq SIOCGIFMETRIC get interface metric struct ifreq SIOCSIFMETRIC set interface metric struct ifreq
ifconf and ifreq structures structifconf { int ifc_len; /* size of associated buffer */ union { caddr_t ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ };
structifreq { #define IFNAMSIZ 16 char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ union { struct sockaddr ifru_addr; /* size = 16 bytes */ struct sockaddr ifru_dstaddr; char ifru_oname[IFNAMSIZ]; /* other if name */ struct sockaddr ifru_broadaddr; int ifru_index; /* interface index */ short ifru_flags; int ifru_metric; char ifru_data[1]; /* interface dependent data */ char ifru_enaddr[6]; int if_muxid[2]; /* mux id's for arp and ip * } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_oname ifr_ifru.ifru_oname /* other if name */ #define ifr_broadaddrifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ #define ifr_enaddr ifr_ifru.ifru_enaddr /* ethernet address */ #define ifr_index ifr_ifru.ifru_index /* interface index */ };
Getting Interface list • get_ifi_info() function • Will return the list of interface information • Each list entry is a structure of type struct ifi_info • Will call ioctl() with request type SIOCGIFCONF to get the list • This call will return a an array of ifreq structures: each structure will include info about the interface • For each returned ifreq structure about an interface, it can get more information by calling ioctl again with a different request type
ifi_info structure get_ifi_info() returns the list of the following structure: #define IFI_NAME 16 /* same as IFNAMSIZ in <net/if.h> */ #define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ struct ifi_info { char ifi_name[IFI_NAME]; /* interface name, null terminated */ u_char ifi_haddr[IFI_HADDR]; /* hardware address */ u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */ short ifi_flags; /* IFF_xxx constants from <net/if.h> */ short ifi_myflags; /* our own IFI_xxx flags */ struct sockaddr *ifi_addr; /* primary address */ struct sockaddr *ifi_brdaddr;/* broadcast address */ struct sockaddr *ifi_dstaddr;/* destination address */ struct ifi_info *ifi_next; /* next of these structures */ };
Use of get_ifi_info Function int main(int argc, char **argv) { struct ifi_info *ifi, *ifihead; struct sockaddr *sa; u_char *ptr; int i, family, doaliases; if (argc != 3) err_quit("usage: prifinfo <inet4|inet6> <doaliases>"); if (strcmp(argv[1], "inet4") == 0) family = AF_INET; #ifdef IPV6 else if (strcmp(argv[1], "inet6") == 0) family = AF_INET6; #endif else err_quit("invalid <address-family>"); doaliases = atoi(argv[2]);
for (ifihead = ifi = Get_ifi_info(family, doaliases); ifi != NULL; ifi = ifi->ifi_next) { printf("%s: <", ifi->ifi_name); if (ifi->ifi_flags & IFF_UP) printf("UP "); if (ifi->ifi_flags & IFF_BROADCAST) printf("BCAST "); if (ifi->ifi_flags & IFF_MULTICAST) printf("MCAST "); if (ifi->ifi_flags & IFF_LOOPBACK) printf("LOOP "); if (ifi->ifi_flags & IFF_POINTOPOINT) printf("P2P "); printf(">\n"); if ( (i = ifi->ifi_hlen) > 0) { ptr = ifi->ifi_haddr; do { printf("%s%x", (i == ifi->ifi_hlen) ? " " : ":", *ptr++); } while (--i > 0); printf("\n"); }
if ( (sa = ifi->ifi_addr) != NULL) printf(" IP addr: %s\n", Sock_ntop_host(sa, sizeof(*sa))); if ( (sa = ifi->ifi_brdaddr) != NULL) printf(" broadcast addr: %s\n", Sock_ntop_host(sa, sizeof(*sa))); if ( (sa = ifi->ifi_dstaddr) != NULL) printf(" destination addr: %s\n", Sock_ntop_host(sa, sizeof(*sa))); } free_ifi_info(ifihead); exit(0); }
Example Run aspendos{korpe}:> prifinfo inet4 doaliases lo0: <UP MCAST LOOP > IP addr: 127.0.0.1 le0: <UP BCAST MCAST > IP addr: 139.179.21.217 broadcast addr: 139.179.21.255
Implementation of get_ifi_info() Function struct ifi_info * get_ifi_info(int family, int doaliases) { struct ifi_info *ifi, *ifihead, **ifipnext; int sockfd, len, lastlen, flags, myflags; char *ptr, *buf, lastname[IFNAMSIZ], *cptr; struct ifconf ifc; struct ifreq *ifr, ifrcopy; struct sockaddr_in *sinptr; sockfd = Socket(AF_INET, SOCK_DGRAM, 0); lastlen = 0; len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ for ( ; ; ) { buf = Malloc(len); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) err_sys("ioctl error"); } else { if (ifc.ifc_len == lastlen) break; /* success, len has not changed */ lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ free(buf); } /* continued on the next page */
ifihead = NULL; ifipnext = &ifihead; lastname[0] = 0; /* end get_ifi_info1 */ /* include get_ifi_info2 */ for (ptr = buf; ptr < buf + ifc.ifc_len; ) { ifr = (struct ifreq *) ptr; len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); switch (ifr->ifr_addr.sa_family) { case AF_INET6: len = sizeof(struct sockaddr_in6); break; case AF_INET: default: len = sizeof(struct sockaddr); break; } ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
if (ifr->ifr_addr.sa_family != family) continue; /* ignore if not desired address family */ myflags = 0; if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) *cptr = 0; /* replace colon will null */ if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { if (doaliases == 0) continue; /* already processed this interface */ myflags = IFI_ALIAS; } memcpy(lastname, ifr->ifr_name, IFNAMSIZ); ifrcopy = *ifr; Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); flags = ifrcopy.ifr_flags; if ((flags & IFF_UP) == 0) continue; /* ignore if interface not up */ ifi = Calloc(1, sizeof(struct ifi_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
ifi->ifi_flags = flags; /* IFF_xxx values */ ifi->ifi_myflags = myflags; /* IFI_xxx values */ memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); ifi->ifi_name[IFI_NAME-1] = '\0'; /* end get_ifi_info2 */ /* include get_ifi_info3 */ switch (ifr->ifr_addr.sa_family) { case AF_INET: sinptr = (struct sockaddr_in *) &ifr->ifr_addr; if (ifi->ifi_addr == NULL) { ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); #ifdef SIOCGIFBRDADDR if (flags & IFF_BROADCAST) { Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); } #endif
#ifdef SIOCGIFDSTADDR if (flags & IFF_POINTOPOINT) { Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); } #endif } break; default: break; } } free(buf); return(ifihead); /* pointer to first structure in linked list */ } /* end get_ifi_info */
ARP Cache Operations struct arpreq { struct sockaddr arp_pa; struct sockaddr arp_flags; int arp_flags; } REQUEST Description Data Type SIOCSARP add a new entry to arp cache struct arpreq SIOCDARP delete an entry from arp cache struct arpreq SIOCGARP get an entry from arp cache struct arpreq
Routing Table Operations struct rtentry defined in <net/route.h> REQUEST Description Data Type SIOCADDRT add an entry to the routing table struct rtentry SIOCDELRT delete an entry from routing table struct rtentry You have to be “root” in order to add and delete routing table entry.
/dev/kmem and sysctl() • There is no ioctl request type for getting the ARP and Routing table entry list. • The list can be obtained by reading the kernel’s memory by opening /dev/kmem and reading from it. • Or you can use the sysctl() function.