-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtm.c
95 lines (78 loc) · 2 KB
/
rtm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "rtm.h"
#define RTM_BUF_SIZE 512
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int
rtm_socket(void)
{
int routefd;
unsigned int rtfilter;
routefd = socket(PF_ROUTE, SOCK_CLOEXEC|SOCK_RAW, AF_INET);
if (-1 == routefd)
return -1;
rtfilter = ROUTE_FILTER(RTM_NEWADDR);
if (-1 == setsockopt(routefd, PF_ROUTE, ROUTE_MSGFILTER,
&rtfilter, (socklen_t)sizeof(rtfilter))) {
close(routefd);
return -1;
}
return routefd;
}
ssize_t
rtm_consume(int routefd, struct rtm_newaddr *dst)
{
assert(dst);
uint8_t buf[RTM_BUF_SIZE], *p;
struct sockaddr **sa;
struct sockaddr_dl **sdl;
struct sockaddr_in **sin;
struct ifa_msghdr *ifam;
if (-1 == read(routefd, buf, sizeof(buf)))
return -1;
p = buf;
sa = (struct sockaddr **)&p;
sdl = (struct sockaddr_dl **)&p;
sin = (struct sockaddr_in **)&p;
ifam = (struct ifa_msghdr *)buf;
p += ifam->ifam_hdrlen;
for (int i = 1; i; i <<= 1) {
if (!(ifam->ifam_addrs & i))
continue;
if (RTA_NETMASK == i) {
dst->rtm_ifmask.s_addr = (*sin)->sin_addr.s_addr;
}
else if (RTA_IFP == i) {
assert((*sdl)->sdl_nlen < sizeof(dst->rtm_ifname));
strncpy(&dst->rtm_ifname[0], (*sdl)->sdl_data, (*sdl)->sdl_nlen);
dst->rtm_ifname[(*sdl)->sdl_nlen] = '\0';
}
else if (RTA_IFA == i) {
dst->rtm_ifaddr.s_addr = (*sin)->sin_addr.s_addr;
}
else if (RTA_BRD == i) {
dst->rtm_ifbcast.s_addr = (*sin)->sin_addr.s_addr;
}
p += ROUNDUP((*sa)->sa_len);
}
syslog(LOG_DEBUG,
"RTM_NEWADDR: msglen=%hu version=%hhu type=%hhu hdrlen=%hu index=%hu tableid=%hu addrs=%#x flags=%#x",
ifam->ifam_msglen,
ifam->ifam_version,
ifam->ifam_type,
ifam->ifam_hdrlen,
ifam->ifam_index,
ifam->ifam_tableid,
ifam->ifam_addrs,
ifam->ifam_flags);
return p - buf;
}