libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / miniupnpd / linux / getroute.c
blob50cd8a4d8569909f9892a4579518008b3334b1c1
1 /* $Id: getroute.c,v 1.4 2013/02/06 10:50:04 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2013 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <syslog.h>
13 #include <linux/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 /*#include <linux/in_route.h>*/
17 #include <linux/netlink.h>
18 #include <linux/rtnetlink.h>
19 #include <libnfnetlink/libnfnetlink.h>
21 #include "../getroute.h"
22 #include "../upnputils.h"
24 int
25 get_src_for_route_to(const struct sockaddr * dst,
26 void * src, size_t * src_len,
27 int * index)
29 int fd = -1;
30 struct nlmsghdr *h;
31 int status;
32 struct {
33 struct nlmsghdr n;
34 struct rtmsg r;
35 char buf[1024];
36 } req;
37 struct sockaddr_nl nladdr;
38 struct iovec iov = {
39 .iov_base = (void*) &req.n,
41 struct msghdr msg = {
42 .msg_name = &nladdr,
43 .msg_namelen = sizeof(nladdr),
44 .msg_iov = &iov,
45 .msg_iovlen = 1,
47 const struct sockaddr_in * dst4;
48 const struct sockaddr_in6 * dst6;
50 memset(&req, 0, sizeof(req));
51 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
52 req.n.nlmsg_flags = NLM_F_REQUEST;
53 req.n.nlmsg_type = RTM_GETROUTE;
54 req.r.rtm_family = dst->sa_family;
55 req.r.rtm_table = 0;
56 req.r.rtm_protocol = 0;
57 req.r.rtm_scope = 0;
58 req.r.rtm_type = 0;
59 req.r.rtm_src_len = 0;
60 req.r.rtm_dst_len = 0;
61 req.r.rtm_tos = 0;
64 char dst_str[128];
65 sockaddr_to_string(dst, dst_str, sizeof(dst_str));
66 syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
68 /* add address */
69 if(dst->sa_family == AF_INET) {
70 dst4 = (const struct sockaddr_in *)dst;
71 nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
72 req.r.rtm_dst_len = 32;
73 } else {
74 dst6 = (const struct sockaddr_in6 *)dst;
75 nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
76 req.r.rtm_dst_len = 128;
79 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
80 if (fd < 0) {
81 syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
82 return -1;
85 memset(&nladdr, 0, sizeof(nladdr));
86 nladdr.nl_family = AF_NETLINK;
88 req.n.nlmsg_seq = 1;
89 iov.iov_len = req.n.nlmsg_len;
91 status = sendmsg(fd, &msg, 0);
93 if (status < 0) {
94 syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
95 goto error;
98 memset(&req, 0, sizeof(req));
100 for(;;) {
101 iov.iov_len = sizeof(req);
102 status = recvmsg(fd, &msg, 0);
103 if(status < 0) {
104 if (errno == EINTR || errno == EAGAIN)
105 continue;
106 syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
107 goto error;
109 if(status == 0) {
110 syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
111 goto error;
113 for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
114 int len = h->nlmsg_len;
115 int l = len - sizeof(*h);
117 if (l<0 || len>status) {
118 if (msg.msg_flags & MSG_TRUNC) {
119 syslog(LOG_ERR, "Truncated message");
121 syslog(LOG_ERR, "malformed message: len=%d", len);
122 goto error;
125 if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
126 syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
127 /* Don't forget to skip that message. */
128 status -= NLMSG_ALIGN(len);
129 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
130 continue;
133 if(h->nlmsg_type == NLMSG_ERROR) {
134 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
135 syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
136 goto error;
138 if(h->nlmsg_type == RTM_NEWROUTE) {
139 struct rtattr * rta;
140 int len = h->nlmsg_len;
141 len -= NLMSG_LENGTH(sizeof(struct rtmsg));
142 for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
143 unsigned char * data = RTA_DATA(rta);
144 if(rta->rta_type == RTA_PREFSRC) {
145 if(src_len && src) {
146 if(*src_len < RTA_PAYLOAD(rta)) {
147 syslog(LOG_WARNING, "cannot copy src: %u<%lu",
148 (unsigned)*src_len, RTA_PAYLOAD(rta));
149 goto error;
151 *src_len = RTA_PAYLOAD(rta);
152 memcpy(src, data, RTA_PAYLOAD(rta));
154 } else if(rta->rta_type == RTA_OIF) {
155 if(index)
156 memcpy(index, data, sizeof(int));
159 close(fd);
160 return 0;
162 status -= NLMSG_ALIGN(len);
163 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
166 syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
167 error:
168 if(fd >= 0)
169 close(fd);
170 return -1;