1 /*
2  *  Simplified Interface To NetLink
3  *
4  *  Copyright (C) 2016-2018 Antonio Quartulli <a@unstable.cc>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2
8  *  as published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program (see the file COPYING included with this
17  *  distribution); if not, write to the Free Software Foundation, Inc.,
18  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #elif defined(_MSC_VER)
24 #include "config-msvc.h"
25 #endif
26 
27 #ifdef TARGET_LINUX
28 
29 #include "syshead.h"
30 
31 #include "errlevel.h"
32 #include "buffer.h"
33 #include "networking.h"
34 
35 #include <errno.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <linux/netlink.h>
41 #include <linux/rtnetlink.h>
42 
43 #define SNDBUF_SIZE (1024 * 2)
44 #define RCVBUF_SIZE (1024 * 4)
45 
46 #define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size)         \
47     {                                                               \
48         if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
49         {                                                           \
50             goto err;                                               \
51         }                                                           \
52     }
53 
54 #define NLMSG_TAIL(nmsg) \
55     ((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
56 
57 /**
58  * Generic address data structure used to pass addresses and prefixes as
59  * argument to AF family agnostic functions
60  */
61 typedef union {
62     in_addr_t ipv4;
63     struct in6_addr ipv6;
64 } inet_address_t;
65 
66 /**
67  * Link state request message
68  */
69 struct sitnl_link_req {
70     struct nlmsghdr n;
71     struct ifinfomsg i;
72     char buf[256];
73 };
74 
75 /**
76  * Address request message
77  */
78 struct sitnl_addr_req {
79     struct nlmsghdr n;
80     struct ifaddrmsg i;
81     char buf[256];
82 };
83 
84 /**
85  * Route request message
86  */
87 struct sitnl_route_req {
88     struct nlmsghdr n;
89     struct rtmsg r;
90     char buf[256];
91 };
92 
93 typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *msg, void *arg);
94 
95 /**
96  * Object returned by route request operation
97  */
98 struct sitnl_route_data_cb {
99     unsigned int iface;
100     inet_address_t gw;
101 };
102 
103 /**
104  * Helper function used to easily add attributes to a rtnl message
105  */
106 static int
sitnl_addattr(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)107 sitnl_addattr(struct nlmsghdr *n, int maxlen, int type, const void *data,
108               int alen)
109 {
110     int len = RTA_LENGTH(alen);
111     struct rtattr *rta;
112 
113     if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
114     {
115         msg(M_WARN, "%s: rtnl: message exceeded bound of %d", __func__,
116             maxlen);
117         return -EMSGSIZE;
118     }
119 
120     rta = NLMSG_TAIL(n);
121     rta->rta_type = type;
122     rta->rta_len = len;
123 
124     if (!data)
125     {
126         memset(RTA_DATA(rta), 0, alen);
127     }
128     else
129     {
130         memcpy(RTA_DATA(rta), data, alen);
131     }
132 
133     n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
134 
135     return 0;
136 }
137 
138 /**
139  * Open RTNL socket
140  */
141 static int
sitnl_socket(void)142 sitnl_socket(void)
143 {
144     int sndbuf = SNDBUF_SIZE;
145     int rcvbuf = RCVBUF_SIZE;
146     int fd;
147 
148     fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
149     if (fd < 0)
150     {
151         msg(M_WARN, "%s: cannot open netlink socket", __func__);
152         return fd;
153     }
154 
155     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0)
156     {
157         msg(M_WARN | M_ERRNO, "%s: SO_SNDBUF", __func__);
158         close(fd);
159         return -1;
160     }
161 
162     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
163     {
164         msg(M_WARN | M_ERRNO, "%s: SO_RCVBUF", __func__);
165         close(fd);
166         return -1;
167     }
168 
169     return fd;
170 }
171 
172 /**
173  * Bind socket to Netlink subsystem
174  */
175 static int
sitnl_bind(int fd,uint32_t groups)176 sitnl_bind(int fd, uint32_t groups)
177 {
178     socklen_t addr_len;
179     struct sockaddr_nl local;
180 
181     CLEAR(local);
182 
183     local.nl_family = AF_NETLINK;
184     local.nl_groups = groups;
185 
186     if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
187     {
188         msg(M_WARN | M_ERRNO, "%s: cannot bind netlink socket", __func__);
189         return -errno;
190     }
191 
192     addr_len = sizeof(local);
193     if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0)
194     {
195         msg(M_WARN | M_ERRNO, "%s: cannot getsockname", __func__);
196         return -errno;
197     }
198 
199     if (addr_len != sizeof(local))
200     {
201         msg(M_WARN, "%s: wrong address length %d", __func__, addr_len);
202         return -EINVAL;
203     }
204 
205     if (local.nl_family != AF_NETLINK)
206     {
207         msg(M_WARN, "%s: wrong address family %d", __func__, local.nl_family);
208         return -EINVAL;
209     }
210 
211     return 0;
212 }
213 
214 /**
215  * Send Netlink message and run callback on reply (if specified)
216  */
217 static int
sitnl_send(struct nlmsghdr * payload,pid_t peer,unsigned int groups,sitnl_parse_reply_cb cb,void * arg_cb)218 sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups,
219            sitnl_parse_reply_cb cb, void *arg_cb)
220 {
221     int len, rem_len, fd, ret, rcv_len;
222     struct sockaddr_nl nladdr;
223     struct nlmsgerr *err;
224     struct nlmsghdr *h;
225     unsigned int seq;
226     char buf[1024 * 16];
227     struct iovec iov =
228     {
229         .iov_base = payload,
230         .iov_len = payload->nlmsg_len,
231     };
232     struct msghdr nlmsg =
233     {
234         .msg_name = &nladdr,
235         .msg_namelen = sizeof(nladdr),
236         .msg_iov = &iov,
237         .msg_iovlen = 1,
238     };
239 
240     CLEAR(nladdr);
241 
242     nladdr.nl_family = AF_NETLINK;
243     nladdr.nl_pid = peer;
244     nladdr.nl_groups = groups;
245 
246     payload->nlmsg_seq = seq = time(NULL);
247 
248     /* no need to send reply */
249     if (!cb)
250     {
251         payload->nlmsg_flags |= NLM_F_ACK;
252     }
253 
254     fd = sitnl_socket();
255     if (fd < 0)
256     {
257         msg(M_WARN | M_ERRNO, "%s: can't open rtnl socket", __func__);
258         return -errno;
259     }
260 
261     ret = sitnl_bind(fd, 0);
262     if (ret < 0)
263     {
264         msg(M_WARN | M_ERRNO, "%s: can't bind rtnl socket", __func__);
265         ret = -errno;
266         goto out;
267     }
268 
269     ret = sendmsg(fd, &nlmsg, 0);
270     if (ret < 0)
271     {
272         msg(M_WARN | M_ERRNO, "%s: rtnl: error on sendmsg()", __func__);
273         ret = -errno;
274         goto out;
275     }
276 
277     /* prepare buffer to store RTNL replies */
278     memset(buf, 0, sizeof(buf));
279     iov.iov_base = buf;
280 
281     while (1)
282     {
283         /*
284          * iov_len is modified by recvmsg(), therefore has to be initialized before
285          * using it again
286          */
287         msg(D_RTNL, "%s: checking for received messages", __func__);
288         iov.iov_len = sizeof(buf);
289         rcv_len = recvmsg(fd, &nlmsg, 0);
290         msg(D_RTNL, "%s: rtnl: received %d bytes", __func__, rcv_len);
291         if (rcv_len < 0)
292         {
293             if ((errno == EINTR) || (errno == EAGAIN))
294             {
295                 msg(D_RTNL, "%s: interrupted call", __func__);
296                 continue;
297             }
298             msg(M_WARN | M_ERRNO, "%s: rtnl: error on recvmsg()", __func__);
299             ret = -errno;
300             goto out;
301         }
302 
303         if (rcv_len == 0)
304         {
305             msg(M_WARN, "%s: rtnl: socket reached unexpected EOF", __func__);
306             ret = -EIO;
307             goto out;
308         }
309 
310         if (nlmsg.msg_namelen != sizeof(nladdr))
311         {
312             msg(M_WARN, "%s: sender address length: %u (expected %zu)",
313                 __func__, nlmsg.msg_namelen, sizeof(nladdr));
314             ret = -EIO;
315             goto out;
316         }
317 
318         h = (struct nlmsghdr *)buf;
319         while (rcv_len >= (int)sizeof(*h))
320         {
321             len = h->nlmsg_len;
322             rem_len = len - sizeof(*h);
323 
324             if ((rem_len < 0) || (len > rcv_len))
325             {
326                 if (nlmsg.msg_flags & MSG_TRUNC)
327                 {
328                     msg(M_WARN, "%s: truncated message", __func__);
329                     ret = -EIO;
330                     goto out;
331                 }
332                 msg(M_WARN, "%s: malformed message: len=%d", __func__, len);
333                 ret = -EIO;
334                 goto out;
335             }
336 
337 /*            if (((int)nladdr.nl_pid != peer) || (h->nlmsg_pid != nladdr.nl_pid)
338  *               || (h->nlmsg_seq != seq))
339  *           {
340  *               rcv_len -= NLMSG_ALIGN(len);
341  *               h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
342  *               msg(M_DEBUG, "%s: skipping unrelated message. nl_pid:%d (peer:%d) nl_msg_pid:%d nl_seq:%d seq:%d",
343  *                   __func__, (int)nladdr.nl_pid, peer, h->nlmsg_pid,
344  *                   h->nlmsg_seq, seq);
345  *               continue;
346  *           }
347  */
348 
349             if (h->nlmsg_type == NLMSG_DONE)
350             {
351                 ret = 0;
352                 goto out;
353             }
354 
355             if (h->nlmsg_type == NLMSG_ERROR)
356             {
357                 err = (struct nlmsgerr *)NLMSG_DATA(h);
358                 if (rem_len < (int)sizeof(struct nlmsgerr))
359                 {
360                     msg(M_WARN, "%s: ERROR truncated", __func__);
361                     ret = -EIO;
362                 }
363                 else
364                 {
365                     if (!err->error)
366                     {
367                         ret = 0;
368                         if (cb)
369                         {
370                             int r = cb(h, arg_cb);
371                             if (r <= 0)
372                             {
373                                 ret = r;
374                             }
375                         }
376                     }
377                     else
378                     {
379                         msg(M_WARN, "%s: rtnl: generic error (%d): %s",
380                             __func__, err->error, strerror(-err->error));
381                         ret = err->error;
382                     }
383                 }
384                 goto out;
385             }
386 
387             if (cb)
388             {
389                 int r = cb(h, arg_cb);
390                 if (r <= 0)
391                 {
392                     ret = r;
393                     goto out;
394                 }
395             }
396             else
397             {
398                 msg(M_WARN, "%s: RTNL: unexpected reply", __func__);
399             }
400 
401             rcv_len -= NLMSG_ALIGN(len);
402             h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
403         }
404 
405         if (nlmsg.msg_flags & MSG_TRUNC)
406         {
407             msg(M_WARN, "%s: message truncated", __func__);
408             continue;
409         }
410 
411         if (rcv_len)
412         {
413             msg(M_WARN, "%s: rtnl: %d not parsed bytes", __func__, rcv_len);
414             ret = -1;
415             goto out;
416         }
417     }
418 out:
419     close(fd);
420 
421     return ret;
422 }
423 
424 typedef struct {
425     int addr_size;
426     inet_address_t gw;
427     char iface[IFNAMSIZ];
428     bool default_only;
429     unsigned int table;
430 } route_res_t;
431 
432 static int
sitnl_route_save(struct nlmsghdr * n,void * arg)433 sitnl_route_save(struct nlmsghdr *n, void *arg)
434 {
435     route_res_t *res = arg;
436     struct rtmsg *r = NLMSG_DATA(n);
437     struct rtattr *rta = RTM_RTA(r);
438     int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
439     unsigned int table, ifindex = 0;
440     void *gw = NULL;
441 
442     /* filter-out non-zero dst prefixes */
443     if (res->default_only && r->rtm_dst_len != 0)
444     {
445         return 1;
446     }
447 
448     /* route table, ignored with RTA_TABLE */
449     table = r->rtm_table;
450 
451     while (RTA_OK(rta, len))
452     {
453         switch (rta->rta_type)
454         {
455             /* route interface */
456             case RTA_OIF:
457                 ifindex = *(unsigned int *)RTA_DATA(rta);
458                 break;
459 
460             /* route prefix */
461             case RTA_DST:
462                 break;
463 
464             /* GW for the route */
465             case RTA_GATEWAY:
466                 gw = RTA_DATA(rta);
467                 break;
468 
469             /* route table */
470             case RTA_TABLE:
471                 table = *(unsigned int *)RTA_DATA(rta);
472                 break;
473         }
474 
475         rta = RTA_NEXT(rta, len);
476     }
477 
478     /* filter out any route not coming from the selected table */
479     if (res->table && res->table != table)
480     {
481         return 1;
482     }
483 
484     if (!if_indextoname(ifindex, res->iface))
485     {
486         msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifname for index %d",
487             __func__, ifindex);
488         return -1;
489     }
490 
491     if (gw)
492     {
493         memcpy(&res->gw, gw, res->addr_size);
494     }
495 
496     return 0;
497 }
498 
499 static int
sitnl_route_best_gw(sa_family_t af_family,const inet_address_t * dst,void * best_gw,char * best_iface)500 sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst,
501                     void *best_gw, char *best_iface)
502 {
503     struct sitnl_route_req req;
504     route_res_t res;
505     int ret = -EINVAL;
506 
507     ASSERT(best_gw);
508     ASSERT(best_iface);
509 
510     CLEAR(req);
511     CLEAR(res);
512 
513     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
514     req.n.nlmsg_type = RTM_GETROUTE;
515     req.n.nlmsg_flags = NLM_F_REQUEST;
516 
517     req.r.rtm_family = af_family;
518 
519     switch (af_family)
520     {
521         case AF_INET:
522             res.addr_size = sizeof(in_addr_t);
523             /*
524              * kernel can't return 0.0.0.0/8 host route, dump all
525              * the routes and filter for 0.0.0.0/0 in cb()
526              */
527             if (!dst || !dst->ipv4)
528             {
529                 req.n.nlmsg_flags |= NLM_F_DUMP;
530                 res.default_only = true;
531                 res.table = RT_TABLE_MAIN;
532             }
533             else
534             {
535                 req.r.rtm_dst_len = 32;
536             }
537             break;
538 
539         case AF_INET6:
540             res.addr_size = sizeof(struct in6_addr);
541             /* kernel can return ::/128 host route */
542             req.r.rtm_dst_len = 128;
543             break;
544 
545         default:
546             /* unsupported */
547             return -EINVAL;
548     }
549 
550     SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, res.addr_size);
551 
552     ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
553     if (ret < 0)
554     {
555         goto err;
556     }
557 
558     /* save result in output variables */
559     memcpy(best_gw, &res.gw, res.addr_size);
560     strncpy(best_iface, res.iface, IFNAMSIZ);
561 err:
562     return ret;
563 
564 }
565 
566 /* used by iproute2 implementation too */
567 int
net_route_v6_best_gw(openvpn_net_ctx_t * ctx,const struct in6_addr * dst,struct in6_addr * best_gw,char * best_iface)568 net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
569                      struct in6_addr *best_gw, char *best_iface)
570 {
571     inet_address_t dst_v6 = {0};
572     char buf[INET6_ADDRSTRLEN];
573     int ret;
574 
575     if (dst)
576     {
577         dst_v6.ipv6 = *dst;
578     }
579 
580     msg(D_ROUTE, "%s query: dst %s", __func__,
581         inet_ntop(AF_INET6, &dst_v6.ipv6, buf, sizeof(buf)));
582 
583     ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
584     if (ret < 0)
585     {
586         return ret;
587     }
588 
589     msg(D_ROUTE, "%s result: via %s dev %s", __func__,
590         inet_ntop(AF_INET6, best_gw, buf, sizeof(buf)), best_iface);
591 
592     return ret;
593 
594 }
595 
596 #ifdef ENABLE_SITNL
597 
598 int
net_ctx_init(struct context * c,openvpn_net_ctx_t * ctx)599 net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
600 {
601     (void)c;
602     (void)ctx;
603 
604     return 0;
605 }
606 
607 void
net_ctx_reset(openvpn_net_ctx_t * ctx)608 net_ctx_reset(openvpn_net_ctx_t *ctx)
609 {
610     (void)ctx;
611 }
612 
613 void
net_ctx_free(openvpn_net_ctx_t * ctx)614 net_ctx_free(openvpn_net_ctx_t *ctx)
615 {
616     (void)ctx;
617 }
618 
619 int
net_route_v4_best_gw(openvpn_net_ctx_t * ctx,const in_addr_t * dst,in_addr_t * best_gw,char * best_iface)620 net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
621                      in_addr_t *best_gw, char *best_iface)
622 {
623     inet_address_t dst_v4 = {0};
624     char buf[INET_ADDRSTRLEN];
625     int ret;
626 
627     if (dst)
628     {
629         dst_v4.ipv4 = htonl(*dst);
630     }
631 
632     msg(D_ROUTE, "%s query: dst %s", __func__,
633         inet_ntop(AF_INET, &dst_v4.ipv4, buf, sizeof(buf)));
634 
635     ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
636     if (ret < 0)
637     {
638         return ret;
639     }
640 
641     msg(D_ROUTE, "%s result: via %s dev %s", __func__,
642         inet_ntop(AF_INET, best_gw, buf, sizeof(buf)), best_iface);
643 
644     /* result is expected in Host Order */
645     *best_gw = ntohl(*best_gw);
646 
647     return ret;
648 }
649 
650 int
net_iface_up(openvpn_net_ctx_t * ctx,const char * iface,bool up)651 net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
652 {
653     struct sitnl_link_req req;
654     int ifindex;
655 
656     CLEAR(req);
657 
658     if (!iface)
659     {
660         msg(M_WARN, "%s: passed NULL interface", __func__);
661         return -EINVAL;
662     }
663 
664     ifindex = if_nametoindex(iface);
665     if (ifindex == 0)
666     {
667         msg(M_WARN, "%s: rtnl: cannot get ifindex for %s: %s", __func__, iface,
668             strerror(errno));
669         return -ENOENT;
670     }
671 
672     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
673     req.n.nlmsg_flags = NLM_F_REQUEST;
674     req.n.nlmsg_type = RTM_NEWLINK;
675 
676     req.i.ifi_family = AF_PACKET;
677     req.i.ifi_index = ifindex;
678     req.i.ifi_change |= IFF_UP;
679     if (up)
680     {
681         req.i.ifi_flags |= IFF_UP;
682     }
683     else
684     {
685         req.i.ifi_flags &= ~IFF_UP;
686     }
687 
688     msg(M_INFO, "%s: set %s %s", __func__, iface, up ? "up" : "down");
689 
690     return sitnl_send(&req.n, 0, 0, NULL, NULL);
691 }
692 
693 int
net_iface_mtu_set(openvpn_net_ctx_t * ctx,const char * iface,uint32_t mtu)694 net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface,
695                   uint32_t mtu)
696 {
697     struct sitnl_link_req req;
698     int ifindex, ret = -1;
699 
700     CLEAR(req);
701 
702     ifindex = if_nametoindex(iface);
703     if (ifindex == 0)
704     {
705         msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
706             iface);
707         return -1;
708     }
709 
710     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
711     req.n.nlmsg_flags = NLM_F_REQUEST;
712     req.n.nlmsg_type = RTM_NEWLINK;
713 
714     req.i.ifi_family = AF_PACKET;
715     req.i.ifi_index = ifindex;
716 
717     SITNL_ADDATTR(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
718 
719     msg(M_INFO, "%s: mtu %u for %s", __func__, mtu, iface);
720 
721     ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
722 err:
723     return ret;
724 }
725 
726 static int
sitnl_addr_set(int cmd,uint32_t flags,int ifindex,sa_family_t af_family,const inet_address_t * local,const inet_address_t * remote,int prefixlen)727 sitnl_addr_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
728                const inet_address_t *local, const inet_address_t *remote,
729                int prefixlen)
730 {
731     struct sitnl_addr_req req;
732     uint32_t size;
733     int ret = -EINVAL;
734 
735     CLEAR(req);
736 
737     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
738     req.n.nlmsg_type = cmd;
739     req.n.nlmsg_flags = NLM_F_REQUEST | flags;
740 
741     req.i.ifa_index = ifindex;
742     req.i.ifa_family = af_family;
743 
744     switch (af_family)
745     {
746         case AF_INET:
747             size = sizeof(struct in_addr);
748             break;
749 
750         case AF_INET6:
751             size = sizeof(struct in6_addr);
752             break;
753 
754         default:
755             msg(M_WARN, "%s: rtnl: unknown address family %d", __func__,
756                 af_family);
757             return -EINVAL;
758     }
759 
760     /* if no prefixlen has been specified, assume host address */
761     if (prefixlen == 0)
762     {
763         prefixlen = size * 8;
764     }
765     req.i.ifa_prefixlen = prefixlen;
766 
767     if (remote)
768     {
769         SITNL_ADDATTR(&req.n, sizeof(req), IFA_ADDRESS, remote, size);
770     }
771 
772     if (local)
773     {
774         SITNL_ADDATTR(&req.n, sizeof(req), IFA_LOCAL, local, size);
775     }
776 
777     ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
778     if (ret == -EEXIST)
779     {
780         ret = 0;
781     }
782 err:
783     return ret;
784 }
785 
786 static int
sitnl_addr_ptp_add(sa_family_t af_family,const char * iface,const inet_address_t * local,const inet_address_t * remote)787 sitnl_addr_ptp_add(sa_family_t af_family, const char *iface,
788                    const inet_address_t *local,
789                    const inet_address_t *remote)
790 {
791     int ifindex;
792 
793     switch (af_family)
794     {
795         case AF_INET:
796         case AF_INET6:
797             break;
798 
799         default:
800             return -EINVAL;
801     }
802 
803     if (!iface)
804     {
805         msg(M_WARN, "%s: passed NULL interface", __func__);
806         return -EINVAL;
807     }
808 
809     ifindex = if_nametoindex(iface);
810     if (ifindex == 0)
811     {
812         msg(M_WARN, "%s: cannot get ifindex for %s: %s", __func__, np(iface),
813             strerror(errno));
814         return -ENOENT;
815     }
816 
817     return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
818                           af_family, local, remote, 0);
819 }
820 
821 static int
sitnl_addr_ptp_del(sa_family_t af_family,const char * iface,const inet_address_t * local)822 sitnl_addr_ptp_del(sa_family_t af_family, const char *iface,
823                    const inet_address_t *local)
824 {
825     int ifindex;
826 
827     switch (af_family)
828     {
829         case AF_INET:
830         case AF_INET6:
831             break;
832 
833         default:
834             return -EINVAL;
835     }
836 
837     if (!iface)
838     {
839         msg(M_WARN, "%s: passed NULL interface", __func__);
840         return -EINVAL;
841     }
842 
843     ifindex = if_nametoindex(iface);
844     if (ifindex == 0)
845     {
846         msg(M_WARN | M_ERRNO, "%s: cannot get ifindex for %s", __func__, iface);
847         return -ENOENT;
848     }
849 
850     return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
851 }
852 
853 static int
sitnl_route_set(int cmd,uint32_t flags,int ifindex,sa_family_t af_family,const void * dst,int prefixlen,const void * gw,enum rt_class_t table,int metric,enum rt_scope_t scope,int protocol,int type)854 sitnl_route_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
855                 const void *dst, int prefixlen,
856                 const void *gw, enum rt_class_t table, int metric,
857                 enum rt_scope_t scope, int protocol, int type)
858 {
859     struct sitnl_route_req req;
860     int ret = -1, size;
861 
862     CLEAR(req);
863 
864     switch (af_family)
865     {
866         case AF_INET:
867             size = sizeof(in_addr_t);
868             break;
869 
870         case AF_INET6:
871             size = sizeof(struct in6_addr);
872             break;
873 
874         default:
875             return -EINVAL;
876     }
877 
878     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
879     req.n.nlmsg_type = cmd;
880     req.n.nlmsg_flags = NLM_F_REQUEST | flags;
881 
882     req.r.rtm_family = af_family;
883     req.r.rtm_scope = scope;
884     req.r.rtm_protocol = protocol;
885     req.r.rtm_type = type;
886     req.r.rtm_dst_len = prefixlen;
887 
888     if (table < 256)
889     {
890         req.r.rtm_table = table;
891     }
892     else
893     {
894         req.r.rtm_table = RT_TABLE_UNSPEC;
895         SITNL_ADDATTR(&req.n, sizeof(req), RTA_TABLE, &table, 4);
896     }
897 
898     if (dst)
899     {
900         SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, size);
901     }
902 
903     if (gw)
904     {
905         SITNL_ADDATTR(&req.n, sizeof(req), RTA_GATEWAY, gw, size);
906     }
907 
908     if (ifindex > 0)
909     {
910         SITNL_ADDATTR(&req.n, sizeof(req), RTA_OIF, &ifindex, 4);
911     }
912 
913     if (metric > 0)
914     {
915         SITNL_ADDATTR(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);
916     }
917 
918     ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
919     if (ret == -EEXIST)
920     {
921         ret = 0;
922     }
923 err:
924     return ret;
925 }
926 
927 static int
sitnl_addr_add(sa_family_t af_family,const char * iface,const inet_address_t * addr,int prefixlen)928 sitnl_addr_add(sa_family_t af_family, const char *iface,
929                const inet_address_t *addr, int prefixlen)
930 {
931     int ifindex;
932 
933     switch (af_family)
934     {
935         case AF_INET:
936         case AF_INET6:
937             break;
938 
939         default:
940             return -EINVAL;
941     }
942 
943     if (!iface)
944     {
945         msg(M_WARN, "%s: passed NULL interface", __func__);
946         return -EINVAL;
947     }
948 
949     ifindex = if_nametoindex(iface);
950     if (ifindex == 0)
951     {
952         msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
953             iface);
954         return -ENOENT;
955     }
956 
957     return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
958                           af_family, addr, NULL, prefixlen);
959 }
960 
961 static int
sitnl_addr_del(sa_family_t af_family,const char * iface,inet_address_t * addr,int prefixlen)962 sitnl_addr_del(sa_family_t af_family, const char *iface, inet_address_t *addr,
963                int prefixlen)
964 {
965     int ifindex;
966 
967     switch (af_family)
968     {
969         case AF_INET:
970         case AF_INET6:
971             break;
972 
973         default:
974             return -EINVAL;
975     }
976 
977     if (!iface)
978     {
979         msg(M_WARN, "%s: passed NULL interface", __func__);
980         return -EINVAL;
981     }
982 
983     ifindex = if_nametoindex(iface);
984     if (ifindex == 0)
985     {
986         msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
987             iface);
988         return -ENOENT;
989     }
990 
991     return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL,
992                           prefixlen);
993 }
994 
995 int
net_addr_v4_add(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * addr,int prefixlen)996 net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
997                 const in_addr_t *addr, int prefixlen)
998 {
999     inet_address_t addr_v4 = { 0 };
1000     char buf[INET_ADDRSTRLEN];
1001 
1002     if (!addr)
1003     {
1004         return -EINVAL;
1005     }
1006 
1007     addr_v4.ipv4 = htonl(*addr);
1008 
1009     msg(M_INFO, "%s: %s/%d dev %s", __func__,
1010         inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)), prefixlen,iface);
1011 
1012     return sitnl_addr_add(AF_INET, iface, &addr_v4, prefixlen);
1013 }
1014 
1015 int
net_addr_v6_add(openvpn_net_ctx_t * ctx,const char * iface,const struct in6_addr * addr,int prefixlen)1016 net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface,
1017                 const struct in6_addr *addr, int prefixlen)
1018 {
1019     inet_address_t addr_v6 = { 0 };
1020     char buf[INET6_ADDRSTRLEN];
1021 
1022     if (!addr)
1023     {
1024         return -EINVAL;
1025     }
1026 
1027     addr_v6.ipv6 = *addr;
1028 
1029     msg(M_INFO, "%s: %s/%d dev %s", __func__,
1030         inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)), prefixlen, iface);
1031 
1032     return sitnl_addr_add(AF_INET6, iface, &addr_v6, prefixlen);
1033 }
1034 
1035 int
net_addr_v4_del(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * addr,int prefixlen)1036 net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
1037                 const in_addr_t *addr, int prefixlen)
1038 {
1039     inet_address_t addr_v4 = { 0 };
1040     char buf[INET_ADDRSTRLEN];
1041 
1042     if (!addr)
1043     {
1044         return -EINVAL;
1045     }
1046 
1047     addr_v4.ipv4 = htonl(*addr);
1048 
1049     msg(M_INFO, "%s: %s dev %s", __func__,
1050         inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)), iface);
1051 
1052     return sitnl_addr_del(AF_INET, iface, &addr_v4, prefixlen);
1053 }
1054 
1055 int
net_addr_v6_del(openvpn_net_ctx_t * ctx,const char * iface,const struct in6_addr * addr,int prefixlen)1056 net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface,
1057                 const struct in6_addr *addr, int prefixlen)
1058 {
1059     inet_address_t addr_v6 = { 0 };
1060     char buf[INET6_ADDRSTRLEN];
1061 
1062     if (!addr)
1063     {
1064         return -EINVAL;
1065     }
1066 
1067     addr_v6.ipv6 = *addr;
1068 
1069     msg(M_INFO, "%s: %s/%d dev %s", __func__,
1070         inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)), prefixlen, iface);
1071 
1072     return sitnl_addr_del(AF_INET6, iface, &addr_v6, prefixlen);
1073 }
1074 
1075 int
net_addr_ptp_v4_add(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * local,const in_addr_t * remote)1076 net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
1077                     const in_addr_t *local, const in_addr_t *remote)
1078 {
1079     inet_address_t local_v4 = { 0 };
1080     inet_address_t remote_v4 = { 0 };
1081     char buf1[INET_ADDRSTRLEN];
1082     char buf2[INET_ADDRSTRLEN];
1083 
1084     if (!local)
1085     {
1086         return -EINVAL;
1087     }
1088 
1089     local_v4.ipv4 = htonl(*local);
1090 
1091     if (remote)
1092     {
1093         remote_v4.ipv4 = htonl(*remote);
1094     }
1095 
1096     msg(M_INFO, "%s: %s peer %s dev %s", __func__,
1097         inet_ntop(AF_INET, &local_v4.ipv4, buf1, sizeof(buf1)),
1098         inet_ntop(AF_INET, &remote_v4.ipv4, buf2, sizeof(buf2)), iface);
1099 
1100     return sitnl_addr_ptp_add(AF_INET, iface, &local_v4, &remote_v4);
1101 }
1102 
1103 int
net_addr_ptp_v4_del(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * local,const in_addr_t * remote)1104 net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
1105                     const in_addr_t *local, const in_addr_t *remote)
1106 {
1107     inet_address_t local_v4 = { 0 };
1108     char buf[INET6_ADDRSTRLEN];
1109 
1110 
1111     if (!local)
1112     {
1113         return -EINVAL;
1114     }
1115 
1116     local_v4.ipv4 = htonl(*local);
1117 
1118     msg(M_INFO, "%s: %s dev %s", __func__,
1119         inet_ntop(AF_INET, &local_v4.ipv4, buf, sizeof(buf)), iface);
1120 
1121     return sitnl_addr_ptp_del(AF_INET, iface, &local_v4);
1122 }
1123 
1124 static int
sitnl_route_add(const char * iface,sa_family_t af_family,const void * dst,int prefixlen,const void * gw,uint32_t table,int metric)1125 sitnl_route_add(const char *iface, sa_family_t af_family, const void *dst,
1126                 int prefixlen, const void *gw, uint32_t table, int metric)
1127 {
1128     enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1129     int ifindex = 0;
1130 
1131     if (iface)
1132     {
1133         ifindex = if_nametoindex(iface);
1134         if (ifindex == 0)
1135         {
1136             msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s",
1137                 __func__, iface);
1138             return -ENOENT;
1139         }
1140     }
1141 
1142     if (table == 0)
1143     {
1144         table = RT_TABLE_MAIN;
1145     }
1146 
1147     if (!gw && iface)
1148     {
1149         scope = RT_SCOPE_LINK;
1150     }
1151 
1152     return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
1153                            af_family, dst, prefixlen, gw, table, metric, scope,
1154                            RTPROT_BOOT, RTN_UNICAST);
1155 }
1156 
1157 int
net_route_v4_add(openvpn_net_ctx_t * ctx,const in_addr_t * dst,int prefixlen,const in_addr_t * gw,const char * iface,uint32_t table,int metric)1158 net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
1159                  const in_addr_t *gw, const char *iface,
1160                  uint32_t table, int metric)
1161 {
1162     in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1163     in_addr_t dst_be = 0, gw_be = 0;
1164     char dst_str[INET_ADDRSTRLEN];
1165     char gw_str[INET_ADDRSTRLEN];
1166 
1167     if (dst)
1168     {
1169         dst_be = htonl(*dst);
1170         dst_ptr = &dst_be;
1171     }
1172 
1173     if (gw)
1174     {
1175         gw_be = htonl(*gw);
1176         gw_ptr = &gw_be;
1177     }
1178 
1179     msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1180         inet_ntop(AF_INET, &dst_be, dst_str, sizeof(dst_str)),
1181         prefixlen, inet_ntop(AF_INET, &gw_be, gw_str, sizeof(gw_str)),
1182         np(iface), table, metric);
1183 
1184     return sitnl_route_add(iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table,
1185                            metric);
1186 }
1187 
1188 int
net_route_v6_add(openvpn_net_ctx_t * ctx,const struct in6_addr * dst,int prefixlen,const struct in6_addr * gw,const char * iface,uint32_t table,int metric)1189 net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
1190                  int prefixlen, const struct in6_addr *gw,
1191                  const char *iface, uint32_t table, int metric)
1192 {
1193     inet_address_t dst_v6 = { 0 };
1194     inet_address_t gw_v6 = { 0 };
1195     char dst_str[INET6_ADDRSTRLEN];
1196     char gw_str[INET6_ADDRSTRLEN];
1197 
1198     if (dst)
1199     {
1200         dst_v6.ipv6 = *dst;
1201     }
1202 
1203     if (gw)
1204     {
1205         gw_v6.ipv6 = *gw;
1206     }
1207 
1208     msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1209         inet_ntop(AF_INET6, &dst_v6.ipv6, dst_str, sizeof(dst_str)),
1210         prefixlen, inet_ntop(AF_INET6, &gw_v6.ipv6, gw_str, sizeof(gw_str)),
1211         np(iface), table, metric);
1212 
1213     return sitnl_route_add(iface, AF_INET6, dst, prefixlen, gw, table,
1214                            metric);
1215 }
1216 
1217 static int
sitnl_route_del(const char * iface,sa_family_t af_family,inet_address_t * dst,int prefixlen,inet_address_t * gw,uint32_t table,int metric)1218 sitnl_route_del(const char *iface, sa_family_t af_family, inet_address_t *dst,
1219                 int prefixlen, inet_address_t *gw, uint32_t table,
1220                 int metric)
1221 {
1222     int ifindex = 0;
1223 
1224     if (iface)
1225     {
1226         ifindex = if_nametoindex(iface);
1227         if (ifindex == 0)
1228         {
1229             msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s",
1230                 __func__, iface);
1231             return -ENOENT;
1232         }
1233     }
1234 
1235     if (table == 0)
1236     {
1237         table = RT_TABLE_MAIN;
1238     }
1239 
1240     return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen,
1241                            gw, table, metric, RT_SCOPE_NOWHERE, 0, 0);
1242 }
1243 
1244 int
net_route_v4_del(openvpn_net_ctx_t * ctx,const in_addr_t * dst,int prefixlen,const in_addr_t * gw,const char * iface,uint32_t table,int metric)1245 net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
1246                  const in_addr_t *gw, const char *iface, uint32_t table,
1247                  int metric)
1248 {
1249     inet_address_t dst_v4 = { 0 };
1250     inet_address_t gw_v4 = { 0 };
1251     char dst_str[INET_ADDRSTRLEN];
1252     char gw_str[INET_ADDRSTRLEN];
1253 
1254     if (dst)
1255     {
1256         dst_v4.ipv4 = htonl(*dst);
1257     }
1258 
1259     if (gw)
1260     {
1261         gw_v4.ipv4 = htonl(*gw);
1262     }
1263 
1264     msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1265         inet_ntop(AF_INET, &dst_v4.ipv4, dst_str, sizeof(dst_str)),
1266         prefixlen, inet_ntop(AF_INET, &gw_v4.ipv4, gw_str, sizeof(gw_str)),
1267         np(iface), table, metric);
1268 
1269     return sitnl_route_del(iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table,
1270                            metric);
1271 }
1272 
1273 int
net_route_v6_del(openvpn_net_ctx_t * ctx,const struct in6_addr * dst,int prefixlen,const struct in6_addr * gw,const char * iface,uint32_t table,int metric)1274 net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
1275                  int prefixlen, const struct in6_addr *gw,
1276                  const char *iface, uint32_t table, int metric)
1277 {
1278     inet_address_t dst_v6 = { 0 };
1279     inet_address_t gw_v6 = { 0 };
1280     char dst_str[INET6_ADDRSTRLEN];
1281     char gw_str[INET6_ADDRSTRLEN];
1282 
1283     if (dst)
1284     {
1285         dst_v6.ipv6 = *dst;
1286     }
1287 
1288     if (gw)
1289     {
1290         gw_v6.ipv6 = *gw;
1291     }
1292 
1293     msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1294         inet_ntop(AF_INET6, &dst_v6.ipv6, dst_str, sizeof(dst_str)),
1295         prefixlen, inet_ntop(AF_INET6, &gw_v6.ipv6, gw_str, sizeof(gw_str)),
1296         np(iface), table, metric);
1297 
1298     return sitnl_route_del(iface, AF_INET6, &dst_v6, prefixlen, &gw_v6,
1299                            table, metric);
1300 }
1301 
1302 #endif /* !ENABLE_SITNL */
1303 
1304 #endif /* TARGET_LINUX */
1305