Download Chapter 16

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Chapter 16.
ioctl Operations
UNIX Network Programming
1
16.1 Introduction
• The ioctl function has traditionally been the system interface
•
•
used for everything that didn’t fit into some other nicely defined
category.
Nevertheless numerous ioctls remain for implementationdependent features related to network programming: obtaining
the interface information, accessing the routing table, ARP cache
A common use of ioctl by network program ( typically server ) is
to obtain information on all the host’s interfaces when the
program starts : the interface addresses, whether the interface
supports broadcasting, whether the interface supports
multicasting, and so on.
UNIX Network Programming
2
16.2 ioctl Function
#include <unistd.h>
int ioctl ( int fd, int request, . . . /* void *arg */ );
Returns: 0 if OK, -1 on error
– The third argument is always a pointer, but the type of pointer
depends on the request.
– We can divide the requests related to networking into sex
categories.
•
•
•
•
•
•
socket operations
file operations
interface operations
ARP cache operations
routing table operations
streams system
UNIX Network Programming
3
UNIX Network Programming
4
16.3 Socket Operations
• SIOCATMASK
• return through the integer pointed to by the third argument a nonzero value if
the socket’s read pointer is currently at the out-of-band mark, of a zero value
if the read pointer is not at the out-of-band mark.
• SIOCGPGRP
• return through the integer pointed to by the third argument either the process
ID or the process group ID that is set to receive the SIGIO or SIGURG signal
for this socket.
• SIOCSPGRP
• set either the process ID or the process group ID to receive the SIGIO or
SIGURG signal for this socket from the integer pointed to by third argument.
UNIX Network Programming
5
16.4 File Operations
• FIONBIO
• the nonblocking flag for the socket is cleared or turned on, depending whether
the third argument to ioclt points to a zero or nonzero value, respectively.
• FIOASYNC
• the flag that governs the receipt of asynchronous I/O signals(SIGIO) for the
socket is cleared or turned on, depending whether the third argument to ioctl
points a zero or nonzero value, respectively.
• FIONREAD
• return in the integer pointed to by the third argument to ioctl the number of
bytes currently in the socket receive buffer.
• FIOSETOWN - Equivalent to SIOCSPGRP for a socket
• FIOGETOWN - Equivalent to SIOCGPGRP for a socket
UNIX Network Programming
6
16.5 Interface Configuration
• From the kernel, get all the network interfaces configured on the
•
•
system
In order to do it, use ioctl with SIOCGIFCONF
Before calling ioctl we allocate a buffer and an ifconf structure
and the initialize the latter.
ifreq{}
ifc_len
ifc_req
Figure 16.3
1024
Initialization of ifconf structure before SIOCGIFCONF.
UNIX Network Programming
7
16.5 Interface Configuration
ifreq{}
ifc_len
ifc_req
64
ifr_name[]
socket
address
structure
ifreq{}
ifr_name[]
socket
address
structure
ifreq{}
Figure 16.4 Values returned by SIOCGIFCONF.
UNIX Network Programming
8
16.5 Interface Configuration
struct ifconf {
int ifc_len;
union {
caddr_t ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req
/* Size of buffer.
*/
/* Buffer address. */
/* Array of structures.
*/
#define IFNAMSIZ 16
struct ifreq {
char ifrn_name[IFNAMSIZ];
/* Interface name, e.g. "en0". */
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short int ifru_flags;
int ifru_matric;
caddr_t ifru_data;
} ifr_ifru;
};
#define ifr_addr
ifr_ifru.ifru_addr
/* address
#define ifr_dstaddr
ifr_ifru.ifru_dstaddr
/* other end of p-p lnk
#define ifr_broadaddr
ifr_ifru.ifru_broadaddr
/* broadcast address
#define ifr_flags
ifr_ifru.ifru_flags
/* flags
#define ifr_metric
ifr_ifru.ifru_ivalue
/* metric
#define ifr_data
ifr_ifru.ifru_data
/* for use by interface
UNIX Network Programming
*/
*/
*/
*/
*/
*/
9
16.6 get_cli_info function
• Since many programs need to know all the interfaces on a system,
we will develop a function of our own named get_ifi_info that
returns a linked list of structures, one for each interface that is
currently “up”.
UNIX Network Programming
10
Figure 16.5 unpifi.h header.
#include "unp.h"
#include <net/if.h>
#define
#define
IFI_NAME
IFI_HADDR
16
8
/* same as IFNAMSIZ in <net/if.h> */
/* 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 */
};
#define IFI_ALIAS
1
/* ifi_addr is an alias */
/* function prototypes */
struct ifi_info
*get_ifi_info(int, int);
struct ifi_info
*Get_ifi_info(int, int);
void
free_ifi_info(struct ifi_info *);
UNIX Network Programming
11
Figure 16.6 prifinfo program that calls our get_ifi_info function. (1/3)
#include "unpifi.h"
int
main(int argc, char **argv)
{
struct ifi_info
struct sockaddr
u_char
int
*ifi, *ifihead;
*sa;
*ptr;
i, family, doaliases;
if (argc != 3)
err_quit("usage: prifinfo <inet4|inet6> <doaliases>");
#ifdef
if (strcmp(argv[1], "inet4") == 0)
family = AF_INET;
IPV6
else if (strcmp(argv[1], "inet6") == 0)
family = AF_INET6;
#endif
else
err_quit("invalid <address-family>");
doaliases = atoi(argv[2]);
UNIX Network Programming
12
Figure 16.6 prifinfo program that calls our get_ifi_info function. (2/3)
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");
UNIX Network Programming
13
Figure 16.6 prifinfo program that calls our get_ifi_info function. (3/3)
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);
}
UNIX Network Programming
14
lib/get_ifi_info.c (1/6)
#include "unpifi.h"
struct ifi_info *
get_ifi_info(int family, int doaliases)
{
struct ifi_info
int
char
struct ifconf
struct ifreq
struct sockaddr_in *sinptr;
*ifi, *ifihead, **ifipnext;
sockfd, len, lastlen, flags, myflags;
*ptr, *buf, lastname[IFNAMSIZ], *cptr;
ifc;
*ifr, ifrcopy;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
lastlen = 0;
len = 100 * sizeof(struct ifreq);
/* initial buffer size guess */
UNIX Network Programming
15
lib/get_ifi_info.c (2/6)
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);
}
ifihead = NULL;
ifipnext = &ifihead;
lastname[0] = 0;
UNIX Network Programming
16
lib/get_ifi_info.c (3/6)
for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
ifr = (struct ifreq *) ptr;
#ifdef
HAVE_SOCKADDR_SA_LEN
len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
#else
switch (ifr->ifr_addr.sa_family) {
#ifdef
IPV6
case AF_INET6:
len = sizeof(struct sockaddr_in6);
break;
#endif
#endif
case AF_INET:
default:
len = sizeof(struct sockaddr);
break;
}
/* HAVE_SOCKADDR_SA_LEN */
ptr += sizeof(ifr->ifr_name) + len;
/* for next one in buffer */
UNIX Network Programming
17
lib/get_ifi_info.c (4/6)
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 */
UNIX Network Programming
18
lib/get_ifi_info.c (5/6)
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';
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));
UNIX Network Programming
19
lib/get_ifi_info.c (6/6)
#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 */
}
UNIX Network Programming
20
Figure 16.10 free_ifi_info function: free dynamic memory allocated by
get _ifi_info.
void
free_ifi_info(struct ifi_info *ifihead)
{
struct ifi_info
*ifi, *ifinext;
for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
if (ifi->ifi_addr != NULL)
free(ifi->ifi_addr);
if (ifi->ifi_brdaddr != NULL)
free(ifi->ifi_brdaddr);
if (ifi->ifi_dstaddr != NULL)
free(ifi->ifi_dstaddr);
ifinext = ifi->ifi_next;
/* can't fetch ifi_next after free() */
free(ifi);
/* the ifi_info{} itself */
}
}
UNIX Network Programming
21
16.7 Interface Operations
• SIOCGIFADDR
•
•
•
•
•
– return the unicast address in the ifr_addr member.
SIOCSIFADDR
– sets the interface address from the ifr_addr member.
SIOCGIFFLAGS
– return the interface flags in the ifr_flags member.
SIOCSIFFLAGS
– sets the interface flags from the ifr_flags member.
SIOCGIFDSTADDR
– return the point-to-point address in the ifr_dstaddr member.
SIOCSIFDSTADDR
– set the point-to-point address from ifr_dstaddr member.
UNIX Network Programming
22
16.7 Interface Operations
• SIOCGIFBRDADDR
•
•
•
•
•
– return the broadcast address in the ifr_broadaddr emember.
SIOCSIFBRDADDR
– set the broadcast address from the ifr_boradaddr member.
SIOCGIFNETMASK
– return the subnet mask in the ifr_addr member.
SIOCSIFNETMASK
– set the subnet mask from the ifr_addr member.
SIOCGIFMETRIC
– return the interface metric in the ifr_metric member.
SIOCSIFMETRIC
– set the interface routing metric from the ifr_metric member.
UNIX Network Programming
23
16.8 ARP Cache Operations
struct arpreq {
struct
sockaddr
struct
sockaddr
int
};
arp_pa;
arp_ha;
arp_flags;
#define
#define
#define
#define
/*
/*
/*
/*
ATF_INUSE
ATF_COM
ATF_PERM
ATF_PUBL
0x01
0x02
0x04
0x08
/* protocol addesss */
/* hardware address */
/* flags */
entry in use */
completed entry (hardware addr valid) */
permanent entry */
published entry (respond for other host) */
• SIOCSARP
•
•
– add a new entry to the ARP cache or modify an existing entry.
SIOCDARP
– delete an entry from the ARP cache.
SIOCGARP
– get an entry from the ARP cache.
UNIX Network Programming
24
Figure 16.12 Print a host’s hardware addresses.
int main(int argc, char **argv)
{
int
char
char
unsigned char
struct arpreq
struct sockaddr_in
family, sockfd;
str[INET6_ADDRSTRLEN];
**pptr;
*ptr;
arpreq;
*sin;
pptr = my_addrs(&family);
for ( ; *pptr != NULL; pptr++) {
printf("%s: ", Inet_ntop(family, *pptr, str, sizeof(str)));
switch (family) {
case AF_INET:
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
sin = (struct sockaddr_in *) &arpreq.arp_pa;
bzero(sin, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
memcpy(&sin->sin_addr, *pptr, sizeof(struct in_addr));
Ioctl(sockfd, SIOCGARP, &arpreq);
ptr = &arpreq.arp_ha.sa_data[0];
printf("%x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1),
*(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
break;
default:
} } exit(0); }
err_quit("unsupported address family: %d", family);
UNIX Network Programming
25
16.9 Routing Table Operations
• Two ioctl requests are provided to operate on the routing table.
• These two requests require that the third argument to ioctl be a
•
pointer to an rtentry structure,which is defined by including the
<net/route.h> header.
Only the superuser can issue these requests.
• SIOCADDRT - add an entry to the routing table.
• SIOCDELRT - delete an entry to the routing table.
UNIX Network Programming
26
Related documents