简体   繁体   中英

using newlib with gcc for routing sockets (unix network programming)

I study from a book called Unix network programming 3rd edition and I wrote the following code and i found it needs a library called if_dl.h which i didn't has cuz i work on ubuntu so i installed the lib-newlib and used it..

but on compile time i get alot of errors that refer to the header files that the newlib has like /usr/lib/newlib/i486-linux-gnu/include/net/route.h:54: error: field ro_dst has incomplete type and same for rt_dst and rt_gateway but there is another problem... that the code uses sa_len which is assumed to be a member in the sockaddr structure.. but the sockaddr only has the sa_family,sa_data members.. so is the problem that i need to work on freeBSD or what?

the code I am talkin about

   #include <stdio.h>
   #include <stdlib.h>
   #include <net/route.h>
   #include <net/if.h>
   #include <net/if_dl.h>
   #include <netinet/in.h>
   #include <sys/socket.h>
   #include <unistd.h>

 2 #define BUFLEN   (sizeof(struct rt_msghdr) + 512)
 3                      /* sizeof(struct sockaddr_in6) * 8 = 192 */
 4 #define SEQ      9999

 5 int
 6 main(int argc, char **argv)
 7 {
 8     int     sockfd;
 9     char   *buf;
10     pid_t   pid;
11     ssize_t n;
12     struct rt_msghdr *rtm;
13     struct sockaddr *sa, *rti_info[RTAX_MAX];
14     struct sockaddr_in *sin;

15     if (argc != 2)
16         err_quit("usage: getrt <IPaddress>");

17     sockfd = Socket(AF_ROUTE, SOCK_RAW, 0); /* need superuser privileges */

18     buf = Calloc(1, BUFLEN);     /* and initialized to 0 */

19     rtm = (struct rt_msghdr *) buf;
20     rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
21     rtm->rtm_version = RTM_VERSION;
22     rtm->rtm_type = RTM_GET;
23     rtm->rtm_addrs = RTA_DST;
24     rtm->rtm_pid = pid = getpid();
25     rtm->rtm_seq = SEQ;

26     sin = (struct sockaddr_in *) (rtm + 1);
27     sin->sin_len = sizeof(struct sockaddr_in);
28     sin->sin_family = AF_INET;
29     Inet_pton(AF_INET, argv[1], &sin->sin_addr);

30     Write(sockfd, rtm, rtm->rtm_msglen);

31     do {
32         n = Read(sockfd, rtm, BUFLEN);
33     } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ ||
34              rtm->rtm_pid != pid);
35     rtm = (struct rt_msghdr *) buf;
36     sa = (struct sockaddr *) (rtm + 1);
37     get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
38     if ( (sa = rti_info[RTAX_DST]) != NULL)
39         printf("dest: %s\n", Sock_ntop_host(sa, sa->sa_len));

40     if ( (sa = rti_info[RTAX_GATEWAY]) != NULL)
41         printf("gateway: %s\n", Sock_ntop_host(sa, sa->sa_len));

42     if ( (sa = rti_info[RTAX_NETMASK]) != NULL)
43         printf("netmask: %s\n", Sock_masktop(sa, sa->sa_len));

44     if ( (sa = rti_info[RTAX_GENMASK]) != NULL)
45         printf("genmask: %s\n", Sock_masktop(sa, sa->sa_len));

46     exit(0);
47 }

2 /*
 3  * Round up 'a' to next multiple of 'size', which must be a power of 2
 4  */
 5 #define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
 6 /*
 7  * Step to next socket address structure;
 8  * if sa_len is 0, assume it is sizeof(u_long).
 9  */
10 #define NEXT_SA(ap) ap = (SA *) \
11     ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (u_long)) : \
12                                        sizeof(u_long)))
13 void
14 get_rtaddrs(int addrs, SA *sa, SA **rti_info)
15 {
16     int     i;
17     for (i = 0; i < RTAX_MAX; i++) {
18         if (addrs & (1 << i)) {
19             rti_info[i] = sa;
20             NEXT_SA(sa);
21         } else
22             rti_info[i] = NULL;
23     }
24 }

 2 const char *
 3 sock_masktop(SA *sa, socklen_t salen)
 4 {
 5     static char str[INET6_ADDRSTRLEN];
 6     unsigned char *ptr = &sa->sa_data[2];
 7     if (sa->sa_len == 0)
 8         return ("0.0.0.0");
 9     else if (sa->sa_len == 5)
10         snprintf(str, sizeof(str), "%d.0.0.0", *ptr);
11     else if (sa->sa_len == 6)
12         snprintf(str, sizeof(str), "%d.%d.0.0", *ptr, *(ptr + 1));
13     else if (sa->sa_len == 7)
14         snprintf(str, sizeof(str), "%d.%d.%d.0", *ptr, *(ptr + 1),
15                  *(ptr + 2));
16     else if (sa->sa_len == 8)
17         snprintf(str, sizeof(str), "%d.%d.%d.%d",
18                  *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
19     else
20         snprintf(str, sizeof(str), "(unknown mask, len = %d, family = %d)",
21                  sa->sa_len, sa->sa_family);
22     return (str);
23 }

That code won't work on Linux. It's implied on page 486 that Stevens tested it on his Solaris, AIX, and FreeBSD test machines (where we would expect it to work). Linux has AF_NETLINK, which is supposed to be equivalent, but does have some minor differences to BSD AF_ROUTE.

Use the definitions in <linux/netlink.h> instead of <net/if_dl.h> on linux. See duplicate question What package do i need to install for using routing sockets? .

As you spotted, sa_len isn't present on linux (nor is it on Solaris, in fact), so all bytes of the address returned will be valid. This would work for sock_masktop :

const char * sock_masktop(SA *sa, socklen_t salen) {
  static char str[INET6_ADDRSTRLEN];
  unsigned char *ptr = &sa->sa_data[2];
  snprintf(str, sizeof(str), "%d.%d.%d.%d",
           *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
  return (str);
}

Why are you using newlib (a C library implementation intended for embedded use) instead of glibc?

try and compile it using glibc (should be installed with your ubuntu distro, if not get libc6-dev installed)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM