Project Alice
Loading...
Searching...
No Matches
gateway.c
Go to the documentation of this file.
1/*
2 Copyright (c) 2014 by Cisco Systems, Inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#else
29#include "default_config.h"
30#endif
31
32#include <ctype.h>
33#include <errno.h>
34#include <sys/types.h>
35#ifndef WIN32
36#include <sys/socket.h> // place it before <net/if.h> struct sockaddr
37#endif //WIN32
38#ifdef __linux__
39#define USE_NETLINK
40#include <linux/types.h>
41#include <linux/netlink.h>
42#include <linux/rtnetlink.h>
43#endif
44
45#include <stdio.h>
46#include <string.h>
47#include <stdlib.h>
48
49#ifndef WIN32
50#include <sys/ioctl.h> // ioctl()
51#include <net/if.h> //struct ifreq
52#endif //WIN32
53#ifdef WIN32
54#undef USE_NETLINK
55#undef USE_SOCKET_ROUTE
56#define USE_WIN32_CODE
57
58#include <winsock2.h>
59#include <ws2ipdef.h>
60#include <Iphlpapi.h>
61#include <ws2tcpip.h>
63#endif
64
65#if defined(__APPLE__) || defined(__FreeBSD__)
66#include <sys/sysctl.h>
67#include <net/if_dl.h> //struct sockaddr_dl
68#define USE_SOCKET_ROUTE
69#endif
70
71#ifndef WIN32
72#include <arpa/inet.h> // inet_addr()
73#include <net/route.h> // struct rt_msghdr
74#ifdef USE_SOCKET_ROUTE
75#include <ifaddrs.h> //getifaddrs() freeifaddrs()
76#endif
77#include <net/if.h>
78#include <net/route.h>
79#include <netinet/in.h> //IPPROTO_GRE sturct sockaddr_in INADDR_ANY
80#endif
81
82#if defined(BSD) || defined(__FreeBSD_kernel__)
83#define USE_SOCKET_ROUTE
84#undef USE_WIN32_CODE
85#endif
86
87#if (defined(sun) && defined(__SVR4))
88#define USE_SOCKET_ROUTE
89#undef USE_WIN32_CODE
90#endif
91
92#include "gateway.h"
93#include "pcp_logger.h"
94#include "unp.h"
95#include "pcp_utils.h"
96
97#ifndef WIN32
98#define SUCCESS (0)
99#define FAILED (-1)
100#define USE_WIN32_CODE
101#endif
102
103#define TO_IPV6MAPPED(x) S6_ADDR32(x)[3] = S6_ADDR32(x)[0];\
104 S6_ADDR32(x)[0] = 0;\
105 S6_ADDR32(x)[1] = 0;\
106 S6_ADDR32(x)[2] = htonl(0xFFFF);
107
108#ifdef USE_NETLINK
109
110#define BUFSIZE 8192
111
112static ssize_t readNlSock(int sockFd, char *bufPtr, unsigned seqNum,
113 unsigned pId)
114{
115 struct nlmsghdr *nlHdr;
116 ssize_t readLen=0, msgLen=0;
117
118 do {
119 /* Receive response from the kernel */
120 readLen=recv(sockFd, bufPtr, BUFSIZE - msgLen, 0);
121 if (readLen == -1) {
122 char errmsg[128];
123 pcp_strerror(errno, errmsg, sizeof(errmsg));
124 PCP_LOG(PCP_LOGLVL_DEBUG, "SOCK READ: %s", errmsg);
125 return -1;
126 }
127
128 nlHdr=(struct nlmsghdr *)bufPtr;
129
130 /* Check if the header is valid */
131 if ((NLMSG_OK(nlHdr, (unsigned)readLen) == 0)
132 || (nlHdr->nlmsg_type == NLMSG_ERROR)) {
133 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Error in received packet");
134 return -1;
135 }
136
137 /* Check if the its the last message */
138 if (nlHdr->nlmsg_type == NLMSG_DONE) {
139 break;
140 } else {
141 /* Else move the pointer to buffer appropriately */
142 bufPtr+=readLen;
143 msgLen+=readLen;
144 }
145
146 /* Check if its a multi part message */
147 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
148 /* return if its not */
149 break;
150 }
151 } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
152 return msgLen;
153}
154
155int getgateways(struct sockaddr_in6 **gws)
156{
157 struct nlmsghdr *nlMsg;
158 char msgBuf[BUFSIZE];
159
160 int sock, msgSeq=0;
161 ssize_t len;
162 int ret;
163
164 if (!gws) {
165 return PCP_ERR_BAD_ARGS;
166 }
167
168 /* Create Socket */
169 sock=socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
170 if (sock < 0) {
171 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Netlink Socket Creation Failed...");
172 return PCP_ERR_UNKNOWN;
173 }
174
175 /* Initialize the buffer */
176 memset(msgBuf, 0, BUFSIZE);
177
178 /* point the header and the msg structure pointers into the buffer */
179 nlMsg=(struct nlmsghdr *)msgBuf;
180
181 /* Fill in the nlmsg header*/
182 nlMsg->nlmsg_len=NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
183 nlMsg->nlmsg_type=RTM_GETROUTE; // Get the routes from kernel routing table.
184
185 nlMsg->nlmsg_flags=NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
186 nlMsg->nlmsg_seq=msgSeq++; // Sequence of the message packet.
187 nlMsg->nlmsg_pid=getpid(); // PID of process sending the request.
188
189 /* Send the request */
190 len=send(sock, nlMsg, nlMsg->nlmsg_len, 0);
191 if (len == -1) {
192 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Write To Netlink Socket Failed...");
194 goto end;
195 }
196
197 /* Read the response */
198 len=readNlSock(sock, msgBuf, msgSeq, getpid());
199 if (len < 0) {
200 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Read From Netlink Socket Failed...");
202 goto end;
203 }
204 /* Parse and print the response */
205 ret=0;
206
207 for (; NLMSG_OK(nlMsg,(unsigned)len); nlMsg=NLMSG_NEXT(nlMsg,len)) {
208 struct rtmsg *rtMsg;
209 struct rtattr *rtAttr;
210 int rtLen;
211 unsigned int scope_id = 0;
212 struct in6_addr addr;
213 int found = 0;
214 rtMsg=(struct rtmsg *)NLMSG_DATA(nlMsg);
215
216 /* If the route is not for AF_INET(6) or does not belong to main
217 routing table then return. */
218 if (((rtMsg->rtm_family != AF_INET) && (rtMsg->rtm_family != AF_INET6))
219 || (rtMsg->rtm_table != RT_TABLE_MAIN)) {
220 continue;
221 }
222
223 /* get the rtattr field */
224 rtAttr=(struct rtattr *)RTM_RTA(rtMsg);
225 rtLen=RTM_PAYLOAD(nlMsg);
226 for (; RTA_OK(rtAttr,rtLen); rtAttr=RTA_NEXT(rtAttr,rtLen)) {
227 size_t rtaLen=RTA_PAYLOAD(rtAttr);
228 if (rtaLen > sizeof(struct in6_addr)) {
229 continue;
230 }
231 if (rtAttr->rta_type == RTA_OIF) {
232 memcpy(&scope_id, RTA_DATA(rtAttr), sizeof(unsigned int));
233 } else if (rtAttr->rta_type == RTA_GATEWAY) {
234 memset(&addr, 0, sizeof(struct in6_addr));
235 memcpy(&addr, RTA_DATA(rtAttr), rtaLen);
236 if (rtMsg->rtm_family == AF_INET) {
237 TO_IPV6MAPPED(&addr);
238 }
239 found=1;
240 }
241 }
242 if (found) {
243 struct sockaddr_in6 *tmp_gws;
244 tmp_gws=(struct sockaddr_in6 *)realloc(*gws,
245 sizeof(struct sockaddr_in6) * (ret + 1));
246 if (!tmp_gws) {
248 "Error allocating memory");
249 if (*gws) {
250 free(*gws);
251 *gws=NULL;
252 }
253 ret=PCP_ERR_NO_MEM;
254 goto end;
255 }
256 *gws=tmp_gws;
257 (*gws + ret)->sin6_family=AF_INET6;
258 memcpy(&((*gws + ret)->sin6_addr), &addr, sizeof(addr));
259 (*gws + ret)->sin6_scope_id=scope_id;
260 SET_SA_LEN(*gws + ret, sizeof(struct sockaddr_in6))
261 ret++;
262 }
263 }
264end:
265 if (close(sock)) {
266 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Close socket error");
267 }
268 return ret;
269}
270
271#endif /* #ifdef USE_NETLINK */
272
273#if defined (USE_WIN32_CODE) && defined(WIN32)
274
275#if 0 // WINVER>=NTDDI_VISTA
276int getgateways(struct in6_addr **gws)
277{
278 PMIB_IPFORWARD_TABLE2 ipf_table;
279 unsigned int i;
280
281 if (!gws) {
282 return PCP_ERR_UNKNOWN;
283 }
284
285 if (GetIpForwardTable2(AF_UNSPEC, &ipf_table) != NO_ERROR) {
286 return PCP_ERR_UNKNOWN;
287 }
288
289 if (!ipf_table) {
290 return PCP_ERR_UNKNOWN;
291 }
292
293 *gws=(struct in6_addr *)calloc(ipf_table->NumEntries,
294 sizeof(struct in6_addr));
295 if (*gws) {
296 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Error allocating memory");
297 return PCP_ERR_NO_MEM;
298 }
299
300 for (i=0; i < ipf_table->NumEntries; ++i) {
301 if (ipf_table->Table[i].NextHop.si_family == AF_INET) {
302 S6_ADDR32((*gws)+i)[0]=
303 ipf_table->Table[i].NextHop.Ipv4.sin_addr.s_addr;
304 TO_IPV6MAPPED(((*gws)+i));
305 }
306 if (ipf_table->Table[i].NextHop.si_family == AF_INET6) {
307 memcpy((*gws) + i, &ipf_table->Table[i].NextHop.Ipv6.sin6_addr,
308 sizeof(struct in6_addr));
309 }
310 }
311 return i;
312}
313#else
314int getgateways(struct sockaddr_in6 **gws)
315{
316 PMIB_IPFORWARDTABLE ipf_table;
317 DWORD ipft_size=0;
318 int i, ret;
319
320 if (!gws) {
321 return PCP_ERR_UNKNOWN;
322 }
323
324 ipf_table=(MIB_IPFORWARDTABLE *)malloc(sizeof(MIB_IPFORWARDTABLE));
325 if (!ipf_table) {
326 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Error allocating memory");
327 ret=PCP_ERR_NO_MEM;
328 goto end;
329 }
330
331 if (GetIpForwardTable(ipf_table, &ipft_size, 0)
332 == ERROR_INSUFFICIENT_BUFFER) {
333 MIB_IPFORWARDTABLE *new_ipf_table;
334 new_ipf_table=(MIB_IPFORWARDTABLE *)realloc(ipf_table, ipft_size);
335 if (!new_ipf_table) {
336 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Error allocating memory");
337 ret=PCP_ERR_NO_MEM;
338 goto end;
339 }
340 ipf_table=new_ipf_table;
341 }
342
343 if (GetIpForwardTable(ipf_table, &ipft_size, 0) != NO_ERROR) {
344 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "GetIpForwardTable failed.");
345 ret=PCP_ERR_UNKNOWN;
346 goto end;
347 }
348
349 *gws=(struct sockaddr_in6 *)calloc(ipf_table->dwNumEntries,
350 sizeof(struct sockaddr_in6));
351 if (!*gws) {
352 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "Error allocating memory");
353 ret=PCP_ERR_NO_MEM;
354 goto end;
355 }
356
357 for (ret=0, i=0; i < (int)ipf_table->dwNumEntries; i++) {
358 if (ipf_table->table[i].dwForwardType == MIB_IPROUTE_TYPE_INDIRECT) {
359 (*gws)[ret].sin6_family = AF_INET6;
360 S6_ADDR32(&(*gws)[ret].sin6_addr)[0]=
361 (uint32_t)ipf_table->table[i].dwForwardNextHop;
362 TO_IPV6MAPPED(&(*gws)[ret].sin6_addr);
363 ret++;
364 }
365 }
366end:
367 if (ipf_table)
368 free(ipf_table);
369
370 return ret;
371}
372#endif
373
374#endif /* #ifdef USE_WIN32_CODE */
375
376#ifdef USE_SOCKET_ROUTE
377
378struct sockaddr;
379struct in6_addr;
380
381/* Adapted from Richard Stevens, UNIX Network Programming */
382
383/*
384 * Round up 'a' to next multiple of 'size', which must be a power of 2
385 */
386#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
387
388/*
389 * Step to next socket address structure;
390 * if sa_len is 0, assume it is sizeof(u_long). Using u_long only works on 32-bit
391 machines. In 64-bit machines it needs to be u_int32_t !!
392 */
393#define NEXT_SA(ap) ap = (struct sockaddr *) \
394 ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof(uint32_t)) : \
395 sizeof(uint32_t)))
396
397/* thanks Stevens for this very handy function */
398static void get_rtaddrs(int addrs, struct sockaddr *sa,
399 struct sockaddr **rti_info)
400{
401 int i;
402
403 for (i=0; i < RTAX_MAX; i++) {
404 if (addrs & (1 << i)) {
405 rti_info[i]=sa;
406 NEXT_SA(sa);
407 } else
408 rti_info[i]=NULL;
409 }
410}
411
412/* Portable (hopefully) function to lookup routing tables. sysctl()'s
413 advantage is that it does not need root permissions. Routing sockets
414 need root permission since it is of type SOCK_RAW. */
415static char *
416net_rt_dump(int type, int family, int flags, size_t *lenp)
417{
418 int mib[6];
419 char *buf;
420
421 mib[0]=CTL_NET;
422 mib[1]=AF_ROUTE;
423 mib[2]=0;
424 mib[3]=family; /* only addresses of this family */
425 mib[4]=type;
426 mib[5]=flags; /* not looked at with NET_RT_DUMP */
427 if (sysctl(mib, 6, NULL, lenp, NULL, 0) < 0)
428 return (NULL);
429
430 if ((buf=malloc(*lenp)) == NULL)
431 return (NULL);
432 if (sysctl(mib, 6, buf, lenp, NULL, 0) < 0)
433 return (NULL);
434
435 return (buf);
436}
437
438/* Performs a route table dump selecting only entries that have Gateways.
439 This means that the return buffer will have many duplicate entries since
440 certain gateways appear multiple times in the routing table.
441
442 It is up to the caller to weed out duplicates
443 */
444int getgateways(struct sockaddr_in6 **gws)
445{
446 char *buf, *next, *lim;
447 size_t len;
448 struct rt_msghdr *rtm;
449 struct sockaddr *sa, *rti_info[RTAX_MAX];
450 int rtcount=0;
451
452 if (!gws) {
453 return PCP_ERR_UNKNOWN;
454 }
455
456 /* net_rt_dump() will return all route entries with gateways */
457 buf=net_rt_dump(NET_RT_FLAGS, 0, RTF_GATEWAY, &len);
458 if (!buf)
459 return PCP_ERR_UNKNOWN;
460 lim=buf + len;
461 for (next=buf; next < lim; next+=rtm->rtm_msglen) {
462 rtm=(struct rt_msghdr *)next;
463 sa=(struct sockaddr *)(rtm + 1);
464 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
465
466 if ((sa=rti_info[RTAX_GATEWAY]) != NULL)
467
468 if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
469 == (RTA_DST | RTA_GATEWAY)) {
470 struct sockaddr_in6 *in6=*gws;
471
472 *gws=(struct sockaddr_in6 *)realloc(*gws,
473 sizeof(struct sockaddr_in6) * (rtcount + 1));
474
475 if (!*gws) {
476 if (in6)
477 free(in6);
478 free(buf);
479 return PCP_ERR_NO_MEM;
480 }
481
482 in6=(*gws) + rtcount;
483 memset(in6, 0, sizeof(struct sockaddr_in6));
484
485 if (sa->sa_family == AF_INET) {
486 /* IPv4 gateways as returned as IPv4 mapped IPv6 addresses */
487 in6->sin6_family = AF_INET6;
488 S6_ADDR32(&in6->sin6_addr)[0]=
489 ((struct sockaddr_in *)(rti_info[RTAX_GATEWAY]))->sin_addr.s_addr;
490 TO_IPV6MAPPED(&in6->sin6_addr);
491 } else if (sa->sa_family == AF_INET6) {
492 memcpy(in6,
493 (struct sockaddr_in6 *)rti_info[RTAX_GATEWAY],
494 sizeof(struct sockaddr_in6));
495 } else {
496 continue;
497 }
498 rtcount++;
499 }
500 }
501 free(buf);
502 return rtcount;
503}
504
505#if 0
506
507/* This structure is used for route operations using routing sockets */
508
509/* I know I could have used sockaddr. But type casting eveywhere is nasty and error prone.
510 I do not believe a few bytes will make much impact and code will become much cleaner */
511
512typedef struct route_op {
513 struct sockaddr_in dst4;
514 struct sockaddr_in mask4;
515 struct sockaddr_in gw4;
516 struct sockaddr_in6 dst6;
517 struct sockaddr_in6 mask6;
518 struct sockaddr_in6 gw6;
519 char ifname[128];
520 uint16_t family;
521} route_op_t;
522
523static int
524get_if_addr_from_name(char *ifname, struct sockaddr *ifsock, int family);
525
526typedef route_op_t route_in_t;
527typedef route_op_t route_out_t;
528
529static int route_get(in_addr_t *dst, in_addr_t *mask, in_addr_t *gateway,
530 char *ifname, route_in_t *routein, route_out_t *routeout);
531static int route_add(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
532 const char *ifname, route_in_t *routein, route_out_t *routeout);
533static int route_change(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
534 const char *ifname, route_in_t *routein, route_out_t *routeout);
535static int route_delete(in_addr_t dst, in_addr_t mask, route_in_t *routein,
536 route_out_t *routeout);
537static int route_get_sa(struct sockaddr *dst, in_addr_t *mask,
538 struct sockaddr *gateway, char *ifname, route_in_t *routein,
539 route_out_t *routeout);
540
541static int find_if_with_name(const char *iface, struct sockaddr_dl *out)
542{
543 struct ifaddrs *ifap, *ifa;
544 struct sockaddr_dl *sdl=NULL;
545
546 if (getifaddrs(&ifap)) {
547 char err_msg[128];
548 pcp_strerror(errno, err_msg, sizeof(err_msg));
549 PCP_LOG(PCP_LOGLVL_DEBUG, "getifaddrs: %s", err_msg);
550 return -1;
551 }
552
553 for (ifa=ifap; ifa; ifa=ifa->ifa_next) {
554 if (ifa->ifa_addr->sa_family == AF_LINK &&
555 /*(ifa->ifa_flags & IFF_POINTOPOINT) && \ */
556 strcmp(iface, ifa->ifa_name) == 0) {
557 sdl=(struct sockaddr_dl *)ifa->ifa_addr;
558 break;
559 }
560 }
561
562 /* If we found it, then use it */
563 if (sdl)
564 bcopy((char *)sdl, (char *)out, (size_t)(sdl->sdl_len));
565
566 freeifaddrs(ifap);
567
568 if (sdl == NULL) {
570 "interface %s not found or invalid(must be p-p)", iface);
571 return -1;
572 }
573 return 0;
574}
575
576static int route_op(u_char op, in_addr_t *dst, in_addr_t *mask,
577 in_addr_t *gateway, char *iface, route_in_t *routein,
578 route_out_t *routeout)
579{
580
581#define ROUNDUP_CT(n) ((n) > 0 ? (1 + (((n) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
582#define ADVANCE_CT(x, n) (x += ROUNDUP_CT((n)->sa_len))
583
584#define NEXTADDR_CT(w, u) \
585 if (msg.msghdr.rtm_addrs & (w)) {\
586 len = ROUNDUP_CT(u.sa.sa_len); bcopy((char *)&(u), cp, len); cp += len;\
587 }
588
589 static int seq=0;
590 int err=0;
591 ssize_t len=0;
592 char *cp;
593 pid_t pid;
594
595 union {
596 struct sockaddr sa;
597 struct sockaddr_in sin;
598 struct sockaddr_dl sdl;
599 struct sockaddr_storage ss; /* added to avoid memory overrun */
600 } so_addr[RTAX_MAX];
601
602 struct {
603 struct rt_msghdr msghdr;
604 char buf[512];
605 } msg;
606
607 bzero(so_addr, sizeof(so_addr));
608 bzero(&msg, sizeof(msg));
609
611 cp=msg.buf;
612 pid=getpid();
613 //msg.msghdr.rtm_msglen = 0;
614 msg.msghdr.rtm_version=RTM_VERSION;
615 //msg.msghdr.rtm_type = RTM_ADD;
616 msg.msghdr.rtm_index=0;
617 msg.msghdr.rtm_pid=pid;
618 msg.msghdr.rtm_addrs=0;
619 msg.msghdr.rtm_seq=++seq;
620 msg.msghdr.rtm_errno=0;
621 msg.msghdr.rtm_flags=0;
622
623 // Destination
624 /* if (dst && *dst != 0xffffffff) { */
625 if (routein && routein->dst4.sin_addr.s_addr != 0xffffffff) {
626 msg.msghdr.rtm_addrs|=RTA_DST;
627
628 so_addr[RTAX_DST].sin.sin_len=sizeof(struct sockaddr_in);
629 so_addr[RTAX_DST].sin.sin_family=AF_INET;
630 so_addr[RTAX_DST].sin.sin_addr.s_addr=mask ? *dst & *mask : *dst;
631 } else {
632 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "invalid(require) dst address");
633 return -1;
634 }
635
636 // Netmask
637 if (mask && *mask != 0xffffffff) {
638 msg.msghdr.rtm_addrs|=RTA_NETMASK;
639
640 so_addr[RTAX_NETMASK].sin.sin_len=sizeof(struct sockaddr_in);
641 so_addr[RTAX_NETMASK].sin.sin_family=AF_INET;
642 so_addr[RTAX_NETMASK].sin.sin_addr.s_addr=*mask;
643
644 } else
645 msg.msghdr.rtm_flags|=RTF_HOST;
646
647 switch (op) {
648 case RTM_ADD:
649 case RTM_CHANGE:
650 msg.msghdr.rtm_type=op;
651 msg.msghdr.rtm_addrs|=RTA_GATEWAY;
652 msg.msghdr.rtm_flags|=RTF_UP;
653
654 // Gateway
655 if ((gateway && *gateway != 0x0 && *gateway != 0xffffffff)) {
656 msg.msghdr.rtm_flags|=RTF_GATEWAY;
657
658 so_addr[RTAX_GATEWAY].sin.sin_len=sizeof(struct sockaddr_in);
659 so_addr[RTAX_GATEWAY].sin.sin_family=AF_INET;
660 so_addr[RTAX_GATEWAY].sin.sin_addr.s_addr=*gateway;
661
662 if (iface != NULL) {
663 msg.msghdr.rtm_addrs|=RTA_IFP;
664 so_addr[RTAX_IFP].sdl.sdl_family=AF_LINK;
665
666 //link_addr(iface, &so_addr[RTAX_IFP].sdl);
667 if (find_if_with_name(iface, &so_addr[RTAX_IFP].sdl) < 0)
668 return -2;
669 }
670
671 } else {
672 if (iface == NULL) {
674 "Requir gateway or iface.");
675 return -1;
676 }
677
678 if (find_if_with_name(iface, &so_addr[RTAX_GATEWAY].sdl) < 0)
679 return -1;
680 }
681 break;
682 case RTM_DELETE:
683 msg.msghdr.rtm_type=op;
684 msg.msghdr.rtm_addrs|=RTA_GATEWAY;
685 msg.msghdr.rtm_flags|=RTF_GATEWAY;
686 break;
687 case RTM_GET:
688 msg.msghdr.rtm_type=op;
689 msg.msghdr.rtm_addrs|=RTA_IFP;
690 so_addr[RTAX_IFP].sa.sa_family=AF_LINK;
691 so_addr[RTAX_IFP].sa.sa_len=sizeof(struct sockaddr_dl);
692 break;
693 default:
694 return EINVAL;
695 }
696
697 NEXTADDR_CT(RTA_DST, so_addr[RTAX_DST]);
698 NEXTADDR_CT(RTA_GATEWAY, so_addr[RTAX_GATEWAY]);
699 NEXTADDR_CT(RTA_NETMASK, so_addr[RTAX_NETMASK]);
700 NEXTADDR_CT(RTA_GENMASK, so_addr[RTAX_GENMASK]);
701 NEXTADDR_CT(RTA_IFP, so_addr[RTAX_IFP]);
702 NEXTADDR_CT(RTA_IFA, so_addr[RTAX_IFA]);
703
704 msg.msghdr.rtm_msglen=len=cp - (char *)&msg;
705
706 int sock=socket(PF_ROUTE, SOCK_RAW, AF_INET);
707 if (sock == -1) {
709 "socket(PF_ROUTE, SOCK_RAW, AF_INET) failed");
710 return -1;
711 }
712
713 if (write(sock, (char *)&msg, len) < 0) {
714 err=-1;
715 goto end;
716 }
717
718 if (op == RTM_GET) {
719 do {
720 len=read(sock, (char *)&msg, sizeof(msg));
721 } while (len > 0
722 && (msg.msghdr.rtm_seq != seq || msg.msghdr.rtm_pid != pid));
723
724 if (len < 0) {
726 "read from routing socket failed");
727 err=-1;
728 } else {
729 struct sockaddr *s_netmask=NULL;
730 struct sockaddr *s_gate=NULL;
731 struct sockaddr_dl *s_ifp=NULL;
732 struct sockaddr *sa;
733 struct sockaddr *rti_info[RTAX_MAX];
734
735 if (msg.msghdr.rtm_version != RTM_VERSION) {
737 "routing message version %d not understood",
738 msg.msghdr.rtm_version);
739 err=-1;
740 goto end;
741 }
742 if (msg.msghdr.rtm_msglen > len) {
744 "message length mismatch, in packet %d, returned %lu",
745 msg.msghdr.rtm_msglen, (unsigned long)len);
746 }
747 if (msg.msghdr.rtm_errno) {
748 PCP_LOG(PCP_LOGLVL_DEBUG, "message indicates error %d, %s",
749 msg.msghdr.rtm_errno, strerror(msg.msghdr.rtm_errno));
750 err=-1;
751 goto end;
752 }
753 cp=msg.buf;
754 if (msg.msghdr.rtm_addrs) {
755
756 sa=(struct sockaddr *)cp;
757 get_rtaddrs(msg.msghdr.rtm_addrs, sa, rti_info);
758
759 if ((sa=rti_info[RTAX_DST]) != NULL) {
760 if (sa->sa_family == AF_INET) {
761 char routeto4_str[INET_ADDRSTRLEN];
762
763 memcpy((void *)&(routeout->dst4), (void *)sa,
764 sizeof(struct sockaddr_in));
765 inet_ntop(AF_INET, &(routein->dst4.sin_addr),
766 routeto4_str, INET_ADDRSTRLEN);
767 //memcpy(routeto4_str, sock_ntop((struct sockaddr *)&(routein->dst4), sizeof(struct sockaddr_in)),
768 // INET_ADDRSTRLEN);
769 /* BSD uses a peculiar nomenclature. 'Route to' is the host for which we are looking up
770 the route and 'destinaton' is the intermediate gateway or the final destination
771 when hosts are in the same LAN */
772 PCP_LOG(PCP_LOGLVL_DEBUG, "Dest: %s",
773 sock_ntop(sa, sa->sa_len));
774 if (msg.msghdr.rtm_flags & RTF_WASCLONED) {
776 "Route to %s in the same subnet",
777 routeto4_str);
778 } else if (msg.msghdr.rtm_flags & RTF_CLONING) {
780 "Route to %s in the same subnet but not up",
781 routeto4_str);
782 } else if (msg.msghdr.rtm_flags & RTF_GATEWAY) {
784 "Route to %s not in the same subnet",
785 routeto4_str);
786 }
787 if (routeout->dst4.sin_addr.s_addr
788 == routein->dst4.sin_addr.s_addr) {
790 "Destination %s same as route to %s",
791 sock_ntop(sa, sa->sa_len), routeto4_str);
792 }
793 }
794 }
795
796 if ((sa=rti_info[RTAX_GATEWAY]) != NULL) {
797 s_gate=sa;
798 PCP_LOG(PCP_LOGLVL_DEBUG, "Gateway: %s \n",
799 sock_ntop(sa, sa->sa_len));
800 if (msg.msghdr.rtm_flags & RTF_GATEWAY) {
801 *gateway=
802 ((struct sockaddr_in *)s_gate)->sin_addr.s_addr;
803 routeout->gw4.sin_addr.s_addr=
804 ((struct sockaddr_in *)s_gate)->sin_addr.s_addr;
805 } else {
806 *gateway=0;
807 }
808
809 }
810
811 if ((sa=rti_info[RTAX_IFP]) != NULL) {
813 "family: %d AF_LINK family : %d \n",
814 sa->sa_family, AF_LINK);
815 if ((sa->sa_family == AF_LINK)
816 && ((struct sockaddr_dl *)sa)->sdl_nlen) {
817 uint32_t slen;
818 s_ifp=(struct sockaddr_dl *)sa;
819 slen=s_ifp->sdl_nlen < IFNAMSIZ ?
820 s_ifp->sdl_nlen : IFNAMSIZ;
821 strncpy(iface, s_ifp->sdl_data, slen);
822 strncpy(&(routeout->ifname[0]), s_ifp->sdl_data, slen);
823 routeout->ifname[slen]='\0';
824 iface[slen]='\0';
826 "Interface name %s and type %d \n",
827 &(routeout->ifname[0]), s_ifp->sdl_type);
828 }
829 }
830 }
831
832 if (mask) {
833 if (*dst == 0)
834 *mask=0;
835 else if (s_netmask)
836 *mask=((struct sockaddr_in *)s_netmask)->sin_addr.s_addr; // there must be something wrong here....Ah..
837 else
838 *mask=0xffffffff; // it is a host
839 }
840
841#if 0
842 if (iface && s_ifp) {
843 strncpy(iface, s_ifp->sdl_data,
844 s_ifp->sdl_nlen < IFNAMSIZ ?
845 s_ifp->sdl_nlen : IFNAMSIZ);
846 iface[IFNAMSIZ - 1]='\0';
847 }
848#endif
849 }
850 }
851
852end:
853 if (close(sock) < 0) {
854 PCP_LOG(PCP_LOGLVL_DEBUG, "%s", "socket close failed");
855 }
856
858 return err;
859#undef MAX_INDEX
860}
861
862static int route_get_sa(struct sockaddr *dst, in_addr_t *mask,
863 struct sockaddr *gateway, char *ifname, route_in_t *routein,
864 route_out_t *routeout)
865{
866#if defined(__APPLE__) || defined(__FreeBSD__)
867 return route_op(RTM_GET, &(((struct sockaddr_in *) dst)->sin_addr.s_addr), mask,
868 &(((struct sockaddr_in *) gateway)->sin_addr.s_addr), ifname, routein, routeout);
869#else
870 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: todo...\n", __FUNCTION__);
871 return 0;
872#endif
873}
874
875static int route_get(in_addr_t *dst, in_addr_t *mask, in_addr_t *gateway,
876 char iface[], route_in_t *routein, route_out_t *routeout)
877{
878#if defined(__APPLE__) || defined(__FreeBSD__)
879 return route_op(RTM_GET, dst, mask, gateway, iface, routein, routeout);
880#else
881 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: todo...\n", __FUNCTION__);
882 return 0;
883#endif
884}
885
886static int route_add(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
887 const char *iface, route_in_t *routein, route_out_t *routeout)
888{
889#if defined(__APPLE__) || defined(__FreeBSD__)
890 return route_op(RTM_ADD, &dst, &mask, &gateway, (char *)iface, routein, routeout);
891#else
892 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: todo...\n", __FUNCTION__);
893 return -1;
894#endif
895}
896
897static int route_change(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
898 const char *iface, route_in_t *routein, route_out_t *routeout)
899{
900#if defined(__APPLE__) || defined(__FreeBSD__)
901 return route_op(RTM_CHANGE, &dst, &mask, &gateway, (char *)iface, routein, routeout);
902#else
903 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: todo...\n", __FUNCTION__);
904 return -1;
905#endif
906}
907
908static int route_delete(in_addr_t dst, in_addr_t mask, route_in_t *routein,
909 route_out_t *routeout)
910{
911#if defined(__APPLE__) || defined(__FreeBSD__)
912 return route_op(RTM_DELETE, &dst, &mask, 0, NULL, routein, routeout);
913#else
914 PCP_LOG(PCP_LOGLVL_DEBUG, "%s: todo...\n", __FUNCTION__);
915 return -1;
916#endif
917}
918
919/* Adapted from Linux manual example */
920
921/* We need to pass the family because an interface might have multiple addresses
922 each assocaited with different family
923 */
924static int get_if_addr_from_name(char *ifname, struct sockaddr *ifsock,
925 int family)
926{
927 struct ifaddrs *ifaddr, *ifa;
928
929 if (getifaddrs(&ifaddr) == -1) {
930 char err_msg[128];
931 pcp_strerror(errno, err_msg, sizeof(err_msg));
932 PCP_LOG(PCP_LOGLVL_DEBUG, "getifaddrs: %s", err_msg);
933 return -1;
934 }
935
936 /* Walk through linked list, maintaining head pointer so we
937 can free list later */
938
939 for (ifa=ifaddr; ifa != NULL; ifa=ifa->ifa_next) {
940 if (ifa->ifa_addr == NULL)
941 continue;
942
943 /* For an AF_INET* interface address, display the address */
944 if (!strcmp(ifname, ifa->ifa_name)
945 && (ifa->ifa_addr->sa_family == family)) {
946 memcpy(ifsock, ifa->ifa_addr, sizeof(struct sockaddr));
947 freeifaddrs(ifaddr);
948 return 0;
949 }
950
951 }
952
953 freeifaddrs(ifaddr);
954 return -1;
955}
956#endif //0
957
958#endif
#define TO_IPV6MAPPED(x)
Definition: gateway.c:103
int getgateways(struct sockaddr_in6 **gws)
float sin(float x) noexcept
Definition: math_fns.hpp:18
void send(sys::state &state, element_base *parent, T value)
uint uint32_t
@ PCP_LOGLVL_ERR
Definition: pcp.h:86
@ PCP_LOGLVL_DEBUG
Definition: pcp.h:90
@ PCP_ERR_NO_MEM
Definition: pcp.h:73
@ PCP_ERR_RECV_FAILED
Definition: pcp.h:71
@ PCP_ERR_BAD_ARGS
Definition: pcp.h:74
@ PCP_ERR_UNKNOWN
Definition: pcp.h:75
@ PCP_ERR_SEND_FAILED
Definition: pcp.h:70
void pcp_strerror(int errnum, char *buf, size_t buflen)
Definition: pcp_logger.c:165
#define PCP_LOG_END(level)
Definition: pcp_logger.h:73
#define PCP_LOG_BEGIN(level)
Definition: pcp_logger.h:75
#define PCP_LOG(level, fmt,...)
Definition: pcp_logger.h:71
#define SET_SA_LEN(s, l)
Definition: pcp_socket.h:119
#define S6_ADDR32(sa6)
Definition: pcp_utils.h:114
#define inet_ntop
#define ssize_t
#define getpid
char * sock_ntop(const struct sockaddr *sa, socklen_t salen)
Definition: sock_ntop.c:58
void err_msg(const char *,...)