Annotation of embedaddon/pimd/netlink.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Fred Griffoul <griffoul@ccrle.nec.de> sent me this file to use
3: * when compiling pimd under Linux.
4: *
5: * There was no copyright message or author name, so I assume he was the
6: * author, and deserves the copyright/credit for it:
7: *
8: * COPYRIGHT/AUTHORSHIP by Fred Griffoul <griffoul@ccrle.nec.de>
9: * (until proven otherwise).
10: */
11:
12: #include <sys/param.h>
13: #include <sys/file.h>
14: #include <sys/socket.h>
15: #include <netdb.h>
16: #include <stdlib.h>
17: #include <strings.h>
18: #include <paths.h>
19: #include "defs.h"
20:
21: #include <linux/rtnetlink.h>
22:
23: int routing_socket = -1;
24: static uint32_t pid; /* pid_t, but /usr/include/linux/netlink.h says __u32 ... */
25: static uint32_t seq;
26:
27: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf);
28:
29: static int addattr32(struct nlmsghdr *n, size_t maxlen, int type, uint32_t data)
30: {
31: int len = RTA_LENGTH(4);
32: struct rtattr *rta;
33:
34: if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
35: return -1;
36:
37: rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
38: rta->rta_type = type;
39: rta->rta_len = len;
40: memcpy(RTA_DATA(rta), &data, 4);
41: n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
42:
43: return 0;
44: }
45:
46: static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
47: {
48: while (RTA_OK(rta, len)) {
49: if (rta->rta_type <= max)
50: tb[rta->rta_type] = rta;
51: rta = RTA_NEXT(rta, len);
52: }
53:
54: if (len)
55: logit(LOG_WARNING, 0, "NETLINK: Deficit in rtattr %d", len);
56:
57: return 0;
58: }
59:
60: /* open and initialize the routing socket */
61: int init_routesock(void)
62: {
63: socklen_t addr_len;
64: struct sockaddr_nl local;
65:
66: routing_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
67: if (routing_socket < 0) {
68: logit(LOG_ERR, errno, "Failed creating netlink socket");
69: return -1;
70: }
71:
72: memset(&local, 0, sizeof(local));
73: local.nl_family = AF_NETLINK;
74: local.nl_groups = 0;
75: if (bind(routing_socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
76: logit(LOG_ERR, errno, "Failed binding to netlink socket");
77: return -1;
78: }
79:
80: addr_len = sizeof(local);
81: if (getsockname(routing_socket, (struct sockaddr *)&local, &addr_len) < 0) {
82: logit(LOG_ERR, errno, "Failed netlink getsockname");
83: return -1;
84: }
85:
86: if (addr_len != sizeof(local)) {
87: logit(LOG_ERR, 0, "Invalid netlink addr len.");
88: return -1;
89: }
90:
91: if (local.nl_family != AF_NETLINK) {
92: logit(LOG_ERR, 0, "Invalid netlink addr family.");
93: return -1;
94: }
95:
96: pid = local.nl_pid;
97: seq = time(NULL);
98:
99: return 0;
100: }
101:
102: /* get the rpf neighbor info */
103: int k_req_incoming(uint32_t source, struct rpfctl *rpf)
104: {
105: int l, rlen;
106: char buf[512];
107: struct nlmsghdr *n = (struct nlmsghdr *)buf;
108: struct rtmsg *r = NLMSG_DATA(n);
109: struct sockaddr_nl addr;
110:
111: rpf->source.s_addr = source;
112: rpf->iif = ALL_VIFS;
113: rpf->rpfneighbor.s_addr = 0;
114:
115: n->nlmsg_type = RTM_GETROUTE;
116: n->nlmsg_flags = NLM_F_REQUEST;
117: n->nlmsg_len = NLMSG_LENGTH(sizeof(*r));
118: n->nlmsg_pid = pid;
119: n->nlmsg_seq = ++seq;
120:
121: memset(r, 0, sizeof(*r));
122: r->rtm_family = AF_INET;
123: r->rtm_dst_len = 32;
124: addattr32(n, sizeof(buf), RTA_DST, rpf->source.s_addr);
125: #ifdef CONFIG_RTNL_OLD_IFINFO
126: r->rtm_optlen = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
127: #endif
128: addr.nl_family = AF_NETLINK;
129: addr.nl_groups = 0;
130: addr.nl_pid = 0;
131:
132: if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
133: IF_DEBUG(DEBUG_RPF)
134: logit(LOG_DEBUG, 0, "NETLINK: ask path to %s", inet_fmt(rpf->source.s_addr, s1, sizeof(s1)));
135: }
136:
137: while ((rlen = sendto(routing_socket, buf, n->nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
138: if (errno == EINTR)
139: continue; /* Received signal, retry syscall. */
140:
141: logit(LOG_WARNING, errno, "Error writing to routing socket");
142: return FALSE;
143: }
144:
145: do {
146: socklen_t alen = sizeof(addr);
147:
148: l = recvfrom(routing_socket, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &alen);
149: if (l < 0) {
150: if (errno == EINTR)
151: continue; /* Received signal, retry syscall. */
152:
153: logit(LOG_WARNING, errno, "Error writing to routing socket");
154: return FALSE;
155: }
156: } while (n->nlmsg_seq != seq || n->nlmsg_pid != pid);
157:
158: if (n->nlmsg_type != RTM_NEWROUTE) {
159: if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
160: if (n->nlmsg_type != NLMSG_ERROR)
161: logit(LOG_WARNING, 0, "netlink: wrong answer type %d", n->nlmsg_type);
162: else
163: logit(LOG_WARNING, -(*(int*)NLMSG_DATA(n)), "netlink get_route");
164: }
165:
166: return FALSE;
167: }
168:
169: return getmsg(NLMSG_DATA(n), l - sizeof(*n), rpf);
170: }
171:
172: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf)
173: {
174: int ifindex;
175: vifi_t vifi;
176: struct uvif *v;
177: struct rtattr *rta[RTA_MAX + 1];
178:
179: if (!rpf) {
180: logit(LOG_WARNING, 0, "Missing rpf pointer to netlink.c:getmsg()!");
181: return FALSE;
182: }
183:
184: rpf->iif = NO_VIF;
185: rpf->rpfneighbor.s_addr = INADDR_ANY;
186:
187: if (rtm->rtm_type == RTN_LOCAL) {
188: IF_DEBUG(DEBUG_RPF)
189: logit(LOG_DEBUG, 0, "NETLINK: local address");
190:
191: if ((rpf->iif = local_address(rpf->source.s_addr)) != MAXVIFS) {
192: rpf->rpfneighbor.s_addr = rpf->source.s_addr;
193:
194: return TRUE;
195: }
196:
197: return FALSE;
198: }
199:
200: if (rtm->rtm_type != RTN_UNICAST) {
201: IF_DEBUG(DEBUG_RPF)
202: logit(LOG_DEBUG, 0, "NETLINK: route type is %d", rtm->rtm_type);
203: return FALSE;
204: }
205:
206: memset(rta, 0, sizeof(rta));
207: parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), msglen - sizeof(*rtm));
208:
209: if (!rta[RTA_OIF]) {
210: logit(LOG_WARNING, 0, "NETLINK: no outbound interface");
211: return FALSE;
212: }
213:
214: /* Get ifindex of outbound interface */
215: ifindex = *(int *)RTA_DATA(rta[RTA_OIF]);
216:
217: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
218: if (v->uv_ifindex == ifindex)
219: break;
220: }
221:
222: if (vifi >= numvifs) {
223: logit(LOG_WARNING, 0, "NETLINK: ifindex=%d, but no vif", ifindex);
224: return FALSE;
225: }
226:
227: /* Found inbound interface in vifi */
228: rpf->iif = vifi;
229:
230: IF_DEBUG(DEBUG_RPF)
231: logit(LOG_DEBUG, 0, "NETLINK: vif %d, ifindex=%d", vifi, ifindex);
232:
233: if (rta[RTA_GATEWAY]) {
234: uint32_t gw = *(uint32_t *)RTA_DATA(rta[RTA_GATEWAY]);
235:
236: IF_DEBUG(DEBUG_RPF)
237: logit(LOG_DEBUG, 0, "NETLINK: gateway is %s", inet_fmt(gw, s1, sizeof(s1)));
238: rpf->rpfneighbor.s_addr = gw;
239: } else {
240: rpf->rpfneighbor.s_addr = rpf->source.s_addr;
241: }
242:
243: return TRUE;
244: }
245:
246: /**
247: * Local Variables:
248: * version-control: t
249: * indent-tabs-mode: t
250: * c-file-style: "ellemtel"
251: * c-basic-offset: 4
252: * End:
253: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>