c - 使用 newlib 和 gcc 进行路由套接字(unix 网络编程)

标签 c unix routes network-programming

我学习的是一本叫Unix网络编程第三版的书 我编写了以下代码,我发现它需要一个名为 if_dl.h 的库 我没有,因为我在 ubuntu 上工作,所以我安装了 lib-newlib 并使用了它..

但是在编译时我收到很多错误,这些错误引用了 newlib 所具有的头文件 /usr/lib/newlib/i486-linux-gnu/include/net/route.h:54:错误:字段 ro_dst 的类型不完整 rt_dst 和 rt_gateway 也一样 但还有另一个问题...... 该代码使用 sa_len ,它被假定为 sockaddr 结构中的成员。 但 sockaddr 只有 sa_family,sa_data 成员.. 那么问题是我需要在 freeBSD 上工作还是什么?

我正在谈论的代码

   #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 }

最佳答案

该代码在 Linux 上不起作用。第 486 页暗示 Stevens 在他的 Solaris、AIX 和 FreeBSD 测试机(我们希望它能工作)上测试了它。 Linux 有 AF_NETLINK,它应该是等效的,但与 BSD AF_ROUTE 确实有一些细微差别。

使用<linux/netlink.h>中的定义而不是<net/if_dl.h>在Linux上。查看重复问题What package do i need to install for using routing sockets? .

正如您所发现的,sa_len 在 Linux 上不存在(事实上,在 Solaris 上也不存在),因此返回的地址的所有字节都将有效。这适用于 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);
}

关于c - 使用 newlib 和 gcc 进行路由套接字(unix 网络编程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5380205/

相关文章:

c - 设置为 CHAR_MAX 的字符值是否保证环绕到 CHAR_MIN?

c - 查看 typedef 替换

unix - Java/Websphere NoSuchProviderException : IBMCertPath 问题

c++ - 无法使用 Fedora 中的 g++

mysql - 基于DNS的反向代理多个mysql主机

iphone - 在 iPhone MapView 上显示当前位置和所需位置之间的路线

c - 如何区分同一套接字上的读写事件?

unix - 使用 openSSL 验证 EU GreenPass

ASP.NET System.Web.Routing 和查询字符串参数

c - Win32 C++ ListView WM_CONTEXTMENU 问题