1*cf5a6c84SAndroid Build Coastguard Worker /* route.c - Display/edit network routing table.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Ranjan Kumar <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Kyungwan Han <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2020 Eric Molitor <[email protected]>
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * No Standard
8*cf5a6c84SAndroid Build Coastguard Worker *
9*cf5a6c84SAndroid Build Coastguard Worker * route add -net target 10.0.0.0 netmask 255.0.0.0 dev eth0
10*cf5a6c84SAndroid Build Coastguard Worker * route del delete
11*cf5a6c84SAndroid Build Coastguard Worker * delete net route, must match netmask, informative error message
12*cf5a6c84SAndroid Build Coastguard Worker *
13*cf5a6c84SAndroid Build Coastguard Worker * mod dyn reinstate metric netmask gw mss window irtt dev
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_SBIN))
16*cf5a6c84SAndroid Build Coastguard Worker config ROUTE
17*cf5a6c84SAndroid Build Coastguard Worker bool "route"
18*cf5a6c84SAndroid Build Coastguard Worker default n
19*cf5a6c84SAndroid Build Coastguard Worker help
20*cf5a6c84SAndroid Build Coastguard Worker usage: route [-ne] [-A [inet|inet6]] [add|del TARGET [OPTIONS]]
21*cf5a6c84SAndroid Build Coastguard Worker
22*cf5a6c84SAndroid Build Coastguard Worker Display, add or delete network routes in the "Forwarding Information Base",
23*cf5a6c84SAndroid Build Coastguard Worker which send packets out a network interface to an address.
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Worker -n Show numerical addresses (no DNS lookups)
26*cf5a6c84SAndroid Build Coastguard Worker -e display netstat fields
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker Assigning an address to an interface automatically creates an appropriate
29*cf5a6c84SAndroid Build Coastguard Worker network route ("ifconfig eth0 10.0.2.15/8" does "route add 10.0.0.0/8 eth0"
30*cf5a6c84SAndroid Build Coastguard Worker for you), although some devices (such as loopback) won't show it in the
31*cf5a6c84SAndroid Build Coastguard Worker table. For machines more than one hop away, you need to specify a gateway
32*cf5a6c84SAndroid Build Coastguard Worker (ala "route add default gw 10.0.2.2").
33*cf5a6c84SAndroid Build Coastguard Worker
34*cf5a6c84SAndroid Build Coastguard Worker The address "default" is a wildcard address (0.0.0.0/0) matching all
35*cf5a6c84SAndroid Build Coastguard Worker packets without a more specific route.
36*cf5a6c84SAndroid Build Coastguard Worker
37*cf5a6c84SAndroid Build Coastguard Worker Available OPTIONS include:
38*cf5a6c84SAndroid Build Coastguard Worker reject - blocking route (force match failure)
39*cf5a6c84SAndroid Build Coastguard Worker dev NAME - force matching packets out this interface (ala "eth0")
40*cf5a6c84SAndroid Build Coastguard Worker netmask - old way of saying things like ADDR/24
41*cf5a6c84SAndroid Build Coastguard Worker gw ADDR - forward packets to gateway ADDR
42*cf5a6c84SAndroid Build Coastguard Worker */
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker #define FOR_route
45*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
46*cf5a6c84SAndroid Build Coastguard Worker #define _LINUX_SYSINFO_H // workaround for musl bug
47*cf5a6c84SAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
48*cf5a6c84SAndroid Build Coastguard Worker
49*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
50*cf5a6c84SAndroid Build Coastguard Worker char *A;
51*cf5a6c84SAndroid Build Coastguard Worker )
52*cf5a6c84SAndroid Build Coastguard Worker
53*cf5a6c84SAndroid Build Coastguard Worker struct _arglist {
54*cf5a6c84SAndroid Build Coastguard Worker char *arg;
55*cf5a6c84SAndroid Build Coastguard Worker int action;
56*cf5a6c84SAndroid Build Coastguard Worker };
57*cf5a6c84SAndroid Build Coastguard Worker
58*cf5a6c84SAndroid Build Coastguard Worker static struct _arglist arglist1[] = {
59*cf5a6c84SAndroid Build Coastguard Worker { "add", 1 }, { "del", 2 },
60*cf5a6c84SAndroid Build Coastguard Worker { "delete", 2 }, { NULL, 0 }
61*cf5a6c84SAndroid Build Coastguard Worker };
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker static struct _arglist arglist2[] = {
64*cf5a6c84SAndroid Build Coastguard Worker { "-net", 1 }, { "-host", 2 },
65*cf5a6c84SAndroid Build Coastguard Worker { NULL, 0 }
66*cf5a6c84SAndroid Build Coastguard Worker };
67*cf5a6c84SAndroid Build Coastguard Worker
xsend(int sockfd,void * buf,size_t len)68*cf5a6c84SAndroid Build Coastguard Worker void xsend(int sockfd, void *buf, size_t len)
69*cf5a6c84SAndroid Build Coastguard Worker {
70*cf5a6c84SAndroid Build Coastguard Worker if (send(sockfd, buf, len, 0) != len) perror_exit("xsend");
71*cf5a6c84SAndroid Build Coastguard Worker }
72*cf5a6c84SAndroid Build Coastguard Worker
xrecv(int sockfd,void * buf,size_t len)73*cf5a6c84SAndroid Build Coastguard Worker int xrecv(int sockfd, void *buf, size_t len)
74*cf5a6c84SAndroid Build Coastguard Worker {
75*cf5a6c84SAndroid Build Coastguard Worker int msg_len = recv(sockfd, buf, len, 0);
76*cf5a6c84SAndroid Build Coastguard Worker if (msg_len < 0) perror_exit("xrecv");
77*cf5a6c84SAndroid Build Coastguard Worker
78*cf5a6c84SAndroid Build Coastguard Worker return msg_len;
79*cf5a6c84SAndroid Build Coastguard Worker }
80*cf5a6c84SAndroid Build Coastguard Worker
addAttr(struct nlmsghdr * nl,int maxlen,void * attr,int type,int len)81*cf5a6c84SAndroid Build Coastguard Worker void addAttr(struct nlmsghdr *nl, int maxlen, void *attr, int type, int len)
82*cf5a6c84SAndroid Build Coastguard Worker {
83*cf5a6c84SAndroid Build Coastguard Worker struct rtattr *rt;
84*cf5a6c84SAndroid Build Coastguard Worker int rtlen = RTA_LENGTH(len);
85*cf5a6c84SAndroid Build Coastguard Worker if (NLMSG_ALIGN(nl->nlmsg_len) + rtlen > maxlen) perror_exit("addAttr");
86*cf5a6c84SAndroid Build Coastguard Worker rt = (struct rtattr*)((char *)nl + NLMSG_ALIGN(nl->nlmsg_len));
87*cf5a6c84SAndroid Build Coastguard Worker rt->rta_type = type;
88*cf5a6c84SAndroid Build Coastguard Worker rt->rta_len = rtlen;
89*cf5a6c84SAndroid Build Coastguard Worker memcpy(RTA_DATA(rt), attr, len);
90*cf5a6c84SAndroid Build Coastguard Worker nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + rtlen;
91*cf5a6c84SAndroid Build Coastguard Worker }
92*cf5a6c84SAndroid Build Coastguard Worker
get_hostname(sa_family_t f,void * a,char * dst,size_t len)93*cf5a6c84SAndroid Build Coastguard Worker static void get_hostname(sa_family_t f, void *a, char *dst, size_t len) {
94*cf5a6c84SAndroid Build Coastguard Worker size_t a_len = (AF_INET6 == f) ? sizeof(struct in6_addr) : sizeof(struct in_addr);
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker struct hostent *host = gethostbyaddr(a, a_len, f);
97*cf5a6c84SAndroid Build Coastguard Worker if (host) xstrncpy(dst, host->h_name, len);
98*cf5a6c84SAndroid Build Coastguard Worker }
99*cf5a6c84SAndroid Build Coastguard Worker
display_routes(sa_family_t f)100*cf5a6c84SAndroid Build Coastguard Worker static void display_routes(sa_family_t f)
101*cf5a6c84SAndroid Build Coastguard Worker {
102*cf5a6c84SAndroid Build Coastguard Worker int fd, msg_hdr_len, route_protocol;
103*cf5a6c84SAndroid Build Coastguard Worker struct {
104*cf5a6c84SAndroid Build Coastguard Worker struct nlmsghdr nl;
105*cf5a6c84SAndroid Build Coastguard Worker struct rtmsg rt;
106*cf5a6c84SAndroid Build Coastguard Worker } req;
107*cf5a6c84SAndroid Build Coastguard Worker struct nlmsghdr buf[8192 / sizeof(struct nlmsghdr)];
108*cf5a6c84SAndroid Build Coastguard Worker struct nlmsghdr *msg_hdr_ptr;
109*cf5a6c84SAndroid Build Coastguard Worker struct rtmsg *route_entry;
110*cf5a6c84SAndroid Build Coastguard Worker struct rtattr *rteattr;
111*cf5a6c84SAndroid Build Coastguard Worker
112*cf5a6c84SAndroid Build Coastguard Worker fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
113*cf5a6c84SAndroid Build Coastguard Worker
114*cf5a6c84SAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
115*cf5a6c84SAndroid Build Coastguard Worker req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
116*cf5a6c84SAndroid Build Coastguard Worker req.nl.nlmsg_type = RTM_GETROUTE;
117*cf5a6c84SAndroid Build Coastguard Worker req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
118*cf5a6c84SAndroid Build Coastguard Worker req.nl.nlmsg_pid = getpid();
119*cf5a6c84SAndroid Build Coastguard Worker req.nl.nlmsg_seq = 1;
120*cf5a6c84SAndroid Build Coastguard Worker req.rt.rtm_family = f;
121*cf5a6c84SAndroid Build Coastguard Worker req.rt.rtm_table = RT_TABLE_MAIN;
122*cf5a6c84SAndroid Build Coastguard Worker xsend(fd, &req, sizeof(req));
123*cf5a6c84SAndroid Build Coastguard Worker
124*cf5a6c84SAndroid Build Coastguard Worker if (f == AF_INET) {
125*cf5a6c84SAndroid Build Coastguard Worker xprintf("Kernel IP routing table\n"
126*cf5a6c84SAndroid Build Coastguard Worker "Destination Gateway Genmask Flags %s Iface\n",
127*cf5a6c84SAndroid Build Coastguard Worker FLAG(e) ? " MSS Window irtt" : "Metric Ref Use");
128*cf5a6c84SAndroid Build Coastguard Worker } else {
129*cf5a6c84SAndroid Build Coastguard Worker xprintf("Kernel IPv6 routing table\n"
130*cf5a6c84SAndroid Build Coastguard Worker "%-31s%-26s Flag Metric Ref Use If\n", "Destination", "Next Hop");
131*cf5a6c84SAndroid Build Coastguard Worker }
132*cf5a6c84SAndroid Build Coastguard Worker
133*cf5a6c84SAndroid Build Coastguard Worker msg_hdr_len = xrecv(fd, buf, sizeof(buf));
134*cf5a6c84SAndroid Build Coastguard Worker msg_hdr_ptr = buf;
135*cf5a6c84SAndroid Build Coastguard Worker while (msg_hdr_ptr->nlmsg_type != NLMSG_DONE) {
136*cf5a6c84SAndroid Build Coastguard Worker while (NLMSG_OK(msg_hdr_ptr, msg_hdr_len)) {
137*cf5a6c84SAndroid Build Coastguard Worker route_entry = NLMSG_DATA(msg_hdr_ptr);
138*cf5a6c84SAndroid Build Coastguard Worker route_protocol = route_entry->rtm_protocol;
139*cf5a6c84SAndroid Build Coastguard Worker
140*cf5a6c84SAndroid Build Coastguard Worker // Annoyingly NLM_F_MATCH is not yet implemented so even if we pass in
141*cf5a6c84SAndroid Build Coastguard Worker // RT_TABLE_MAIN with RTM_GETROUTE it still returns everything so we
142*cf5a6c84SAndroid Build Coastguard Worker // have to filter here.
143*cf5a6c84SAndroid Build Coastguard Worker if (route_entry->rtm_table == RT_TABLE_MAIN) {
144*cf5a6c84SAndroid Build Coastguard Worker int route_attribute_len;
145*cf5a6c84SAndroid Build Coastguard Worker char dest[INET6_ADDRSTRLEN], gate[INET6_ADDRSTRLEN], netmask[32],
146*cf5a6c84SAndroid Build Coastguard Worker flags[10] = "U", if_name[IF_NAMESIZE] = "-";
147*cf5a6c84SAndroid Build Coastguard Worker unsigned priority = 0, mss = 0, win = 0, irtt = 0, ref = 0, use = 0,
148*cf5a6c84SAndroid Build Coastguard Worker route_netmask, metric_len;
149*cf5a6c84SAndroid Build Coastguard Worker struct in_addr netmask_addr;
150*cf5a6c84SAndroid Build Coastguard Worker struct rtattr *metric;
151*cf5a6c84SAndroid Build Coastguard Worker struct rta_cacheinfo *cache_info;
152*cf5a6c84SAndroid Build Coastguard Worker
153*cf5a6c84SAndroid Build Coastguard Worker if (f == AF_INET) {
154*cf5a6c84SAndroid Build Coastguard Worker strcpy(dest, FLAG(n) ? "0.0.0.0" : "default");
155*cf5a6c84SAndroid Build Coastguard Worker strcpy(gate, FLAG(n) ? "*" : "0.0.0.0");
156*cf5a6c84SAndroid Build Coastguard Worker strcpy(netmask, "0.0.0.0");
157*cf5a6c84SAndroid Build Coastguard Worker } else {
158*cf5a6c84SAndroid Build Coastguard Worker strcpy(dest, "::");
159*cf5a6c84SAndroid Build Coastguard Worker strcpy(gate, "::");
160*cf5a6c84SAndroid Build Coastguard Worker }
161*cf5a6c84SAndroid Build Coastguard Worker
162*cf5a6c84SAndroid Build Coastguard Worker route_netmask = route_entry->rtm_dst_len;
163*cf5a6c84SAndroid Build Coastguard Worker if (route_netmask == 0) netmask_addr.s_addr = ~((in_addr_t) -1);
164*cf5a6c84SAndroid Build Coastguard Worker else netmask_addr.s_addr = htonl(~((1 << (32 - route_netmask)) - 1));
165*cf5a6c84SAndroid Build Coastguard Worker inet_ntop(AF_INET, &netmask_addr, netmask, sizeof(netmask));
166*cf5a6c84SAndroid Build Coastguard Worker
167*cf5a6c84SAndroid Build Coastguard Worker rteattr = RTM_RTA(route_entry);
168*cf5a6c84SAndroid Build Coastguard Worker route_attribute_len = RTM_PAYLOAD(msg_hdr_ptr);
169*cf5a6c84SAndroid Build Coastguard Worker while (RTA_OK(rteattr, route_attribute_len)) {
170*cf5a6c84SAndroid Build Coastguard Worker switch (rteattr->rta_type) {
171*cf5a6c84SAndroid Build Coastguard Worker case RTA_DST:
172*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(n)) inet_ntop(f, RTA_DATA(rteattr), dest, sizeof(dest));
173*cf5a6c84SAndroid Build Coastguard Worker else get_hostname(f, RTA_DATA(rteattr), dest, sizeof(dest));
174*cf5a6c84SAndroid Build Coastguard Worker break;
175*cf5a6c84SAndroid Build Coastguard Worker
176*cf5a6c84SAndroid Build Coastguard Worker case RTA_GATEWAY:
177*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(n)) inet_ntop(f, RTA_DATA(rteattr), gate, sizeof(dest));
178*cf5a6c84SAndroid Build Coastguard Worker else get_hostname(f, RTA_DATA(rteattr), gate, sizeof(dest));
179*cf5a6c84SAndroid Build Coastguard Worker strcat(flags, "G");
180*cf5a6c84SAndroid Build Coastguard Worker break;
181*cf5a6c84SAndroid Build Coastguard Worker
182*cf5a6c84SAndroid Build Coastguard Worker case RTA_PRIORITY:
183*cf5a6c84SAndroid Build Coastguard Worker priority = *(unsigned *)RTA_DATA(rteattr);
184*cf5a6c84SAndroid Build Coastguard Worker break;
185*cf5a6c84SAndroid Build Coastguard Worker
186*cf5a6c84SAndroid Build Coastguard Worker case RTA_OIF:
187*cf5a6c84SAndroid Build Coastguard Worker if_indextoname(*(int *)RTA_DATA(rteattr), if_name);
188*cf5a6c84SAndroid Build Coastguard Worker break;
189*cf5a6c84SAndroid Build Coastguard Worker
190*cf5a6c84SAndroid Build Coastguard Worker case RTA_METRICS:
191*cf5a6c84SAndroid Build Coastguard Worker metric_len = RTA_PAYLOAD(rteattr);
192*cf5a6c84SAndroid Build Coastguard Worker for (metric = RTA_DATA(rteattr); RTA_OK(metric, metric_len);
193*cf5a6c84SAndroid Build Coastguard Worker metric = RTA_NEXT(metric, metric_len))
194*cf5a6c84SAndroid Build Coastguard Worker if (metric->rta_type == RTAX_ADVMSS)
195*cf5a6c84SAndroid Build Coastguard Worker mss = *(unsigned *)RTA_DATA(metric);
196*cf5a6c84SAndroid Build Coastguard Worker else if (metric->rta_type == RTAX_WINDOW)
197*cf5a6c84SAndroid Build Coastguard Worker win = *(unsigned *)RTA_DATA(metric);
198*cf5a6c84SAndroid Build Coastguard Worker else if (metric->rta_type == RTAX_RTT)
199*cf5a6c84SAndroid Build Coastguard Worker irtt = (*(unsigned *)RTA_DATA(metric))/8;
200*cf5a6c84SAndroid Build Coastguard Worker break;
201*cf5a6c84SAndroid Build Coastguard Worker
202*cf5a6c84SAndroid Build Coastguard Worker case RTA_CACHEINFO:
203*cf5a6c84SAndroid Build Coastguard Worker cache_info = RTA_DATA(rteattr);
204*cf5a6c84SAndroid Build Coastguard Worker ref = cache_info->rta_clntref;
205*cf5a6c84SAndroid Build Coastguard Worker use = cache_info->rta_used;
206*cf5a6c84SAndroid Build Coastguard Worker break;
207*cf5a6c84SAndroid Build Coastguard Worker }
208*cf5a6c84SAndroid Build Coastguard Worker
209*cf5a6c84SAndroid Build Coastguard Worker rteattr = RTA_NEXT(rteattr, route_attribute_len);
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker if (route_entry->rtm_type == RTN_UNREACHABLE) flags[0] = '!';
213*cf5a6c84SAndroid Build Coastguard Worker if (route_netmask == 32) strcat(flags, "H");
214*cf5a6c84SAndroid Build Coastguard Worker if (route_protocol == RTPROT_REDIRECT) strcat(flags, "D");
215*cf5a6c84SAndroid Build Coastguard Worker
216*cf5a6c84SAndroid Build Coastguard Worker if (f == AF_INET) {
217*cf5a6c84SAndroid Build Coastguard Worker xprintf("%-15.15s %-15.15s %-16s%-6s", dest, gate, netmask, flags);
218*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(e)) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, if_name);
219*cf5a6c84SAndroid Build Coastguard Worker else xprintf("%-6d %-2d %7d %s\n", priority, ref, use, if_name);
220*cf5a6c84SAndroid Build Coastguard Worker } else {
221*cf5a6c84SAndroid Build Coastguard Worker char *dest_with_mask = xmprintf("%s/%u", dest, route_netmask);
222*cf5a6c84SAndroid Build Coastguard Worker xprintf("%-30s %-26s %-4s %-6d %-4d %2d %-8s\n",
223*cf5a6c84SAndroid Build Coastguard Worker dest_with_mask, gate, flags, priority, ref, use, if_name);
224*cf5a6c84SAndroid Build Coastguard Worker free(dest_with_mask);
225*cf5a6c84SAndroid Build Coastguard Worker }
226*cf5a6c84SAndroid Build Coastguard Worker }
227*cf5a6c84SAndroid Build Coastguard Worker msg_hdr_ptr = NLMSG_NEXT(msg_hdr_ptr, msg_hdr_len);
228*cf5a6c84SAndroid Build Coastguard Worker }
229*cf5a6c84SAndroid Build Coastguard Worker
230*cf5a6c84SAndroid Build Coastguard Worker msg_hdr_len = xrecv(fd, buf, sizeof(buf));
231*cf5a6c84SAndroid Build Coastguard Worker msg_hdr_ptr = buf;
232*cf5a6c84SAndroid Build Coastguard Worker }
233*cf5a6c84SAndroid Build Coastguard Worker
234*cf5a6c84SAndroid Build Coastguard Worker xclose(fd);
235*cf5a6c84SAndroid Build Coastguard Worker }
236*cf5a6c84SAndroid Build Coastguard Worker
237*cf5a6c84SAndroid Build Coastguard Worker // find parameter (add/del/net/host) in list, return appropriate action or 0.
get_action(char *** argv,struct _arglist * list)238*cf5a6c84SAndroid Build Coastguard Worker static int get_action(char ***argv, struct _arglist *list)
239*cf5a6c84SAndroid Build Coastguard Worker {
240*cf5a6c84SAndroid Build Coastguard Worker struct _arglist *alist;
241*cf5a6c84SAndroid Build Coastguard Worker
242*cf5a6c84SAndroid Build Coastguard Worker if (!**argv) return 0;
243*cf5a6c84SAndroid Build Coastguard Worker for (alist = list; alist->arg; alist++) { //find the given parameter in list
244*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(**argv, alist->arg)) {
245*cf5a6c84SAndroid Build Coastguard Worker *argv += 1;
246*cf5a6c84SAndroid Build Coastguard Worker return alist->action;
247*cf5a6c84SAndroid Build Coastguard Worker }
248*cf5a6c84SAndroid Build Coastguard Worker }
249*cf5a6c84SAndroid Build Coastguard Worker return 0;
250*cf5a6c84SAndroid Build Coastguard Worker }
251*cf5a6c84SAndroid Build Coastguard Worker
252*cf5a6c84SAndroid Build Coastguard Worker // add/del a route.
setroute(sa_family_t f,char ** argv)253*cf5a6c84SAndroid Build Coastguard Worker static void setroute(sa_family_t f, char **argv)
254*cf5a6c84SAndroid Build Coastguard Worker {
255*cf5a6c84SAndroid Build Coastguard Worker char *tgtip;
256*cf5a6c84SAndroid Build Coastguard Worker int sockfd, arg2_action;
257*cf5a6c84SAndroid Build Coastguard Worker int action = get_action(&argv, arglist1); //verify the arg for add/del.
258*cf5a6c84SAndroid Build Coastguard Worker struct nlmsghdr buf[8192 / sizeof(struct nlmsghdr)];
259*cf5a6c84SAndroid Build Coastguard Worker struct nlmsghdr *nlMsg;
260*cf5a6c84SAndroid Build Coastguard Worker struct rtmsg *rtMsg;
261*cf5a6c84SAndroid Build Coastguard Worker
262*cf5a6c84SAndroid Build Coastguard Worker if (!action || !*argv) help_exit("setroute");
263*cf5a6c84SAndroid Build Coastguard Worker arg2_action = get_action(&argv, arglist2); //verify the arg for -net or -host
264*cf5a6c84SAndroid Build Coastguard Worker if (!*argv) help_exit("setroute");
265*cf5a6c84SAndroid Build Coastguard Worker tgtip = *argv++;
266*cf5a6c84SAndroid Build Coastguard Worker sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
267*cf5a6c84SAndroid Build Coastguard Worker memset(buf, 0, sizeof(buf));
268*cf5a6c84SAndroid Build Coastguard Worker nlMsg = (struct nlmsghdr *) buf;
269*cf5a6c84SAndroid Build Coastguard Worker rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);
270*cf5a6c84SAndroid Build Coastguard Worker
271*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
272*cf5a6c84SAndroid Build Coastguard Worker
273*cf5a6c84SAndroid Build Coastguard Worker //TODO(emolitor): Improve action and arg2_action handling
274*cf5a6c84SAndroid Build Coastguard Worker if (action == 1) { // Add
275*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_type = RTM_NEWROUTE;
276*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
277*cf5a6c84SAndroid Build Coastguard Worker } else { // Delete
278*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_type = RTM_DELROUTE;
279*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_flags = NLM_F_REQUEST;
280*cf5a6c84SAndroid Build Coastguard Worker }
281*cf5a6c84SAndroid Build Coastguard Worker
282*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_pid = getpid();
283*cf5a6c84SAndroid Build Coastguard Worker nlMsg->nlmsg_seq = 1;
284*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_family = f;
285*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_table = RT_TABLE_UNSPEC;
286*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_type = RTN_UNICAST;
287*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_protocol = RTPROT_UNSPEC;
288*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_flags = RTM_F_NOTIFY;
289*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_dst_len = rtMsg->rtm_src_len = (f == AF_INET) ? 32 : 128;
290*cf5a6c84SAndroid Build Coastguard Worker
291*cf5a6c84SAndroid Build Coastguard Worker if (arg2_action == 2) rtMsg->rtm_scope = RT_SCOPE_HOST;
292*cf5a6c84SAndroid Build Coastguard Worker
293*cf5a6c84SAndroid Build Coastguard Worker size_t addr_len = sizeof(struct in_addr);
294*cf5a6c84SAndroid Build Coastguard Worker if (f == AF_INET6) addr_len = sizeof(struct in6_addr);
295*cf5a6c84SAndroid Build Coastguard Worker unsigned char addr[sizeof(struct in6_addr)] = {0,};
296*cf5a6c84SAndroid Build Coastguard Worker
297*cf5a6c84SAndroid Build Coastguard Worker for (; *argv; argv++) {
298*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(*argv, "mod")) continue;
299*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(*argv, "dyn")) continue;
300*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(*argv, "reinstate")) continue;
301*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(*argv, "reject")) rtMsg->rtm_type = RTN_UNREACHABLE;
302*cf5a6c84SAndroid Build Coastguard Worker else {
303*cf5a6c84SAndroid Build Coastguard Worker if (!argv[1]) show_help(stdout, 1);
304*cf5a6c84SAndroid Build Coastguard Worker
305*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(*argv, "metric")) {
306*cf5a6c84SAndroid Build Coastguard Worker unsigned int priority = atolx_range(argv[1], 0, UINT_MAX);
307*cf5a6c84SAndroid Build Coastguard Worker addAttr(nlMsg, sizeof(toybuf), &priority, RTA_PRIORITY, sizeof(unsigned int));
308*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "netmask")) {
309*cf5a6c84SAndroid Build Coastguard Worker uint32_t netmask;
310*cf5a6c84SAndroid Build Coastguard Worker char *ptr;
311*cf5a6c84SAndroid Build Coastguard Worker uint32_t naddr[4] = {0,};
312*cf5a6c84SAndroid Build Coastguard Worker uint64_t plen;
313*cf5a6c84SAndroid Build Coastguard Worker
314*cf5a6c84SAndroid Build Coastguard Worker netmask = (f == AF_INET6) ? 128 : 32; // set default netmask
315*cf5a6c84SAndroid Build Coastguard Worker plen = strtoul(argv[1], &ptr, 0);
316*cf5a6c84SAndroid Build Coastguard Worker
317*cf5a6c84SAndroid Build Coastguard Worker if (!ptr || ptr == argv[1] || *ptr || !plen || plen > netmask) {
318*cf5a6c84SAndroid Build Coastguard Worker if (!inet_pton(f, argv[1], &naddr)) error_exit("invalid netmask");
319*cf5a6c84SAndroid Build Coastguard Worker if (f == AF_INET) {
320*cf5a6c84SAndroid Build Coastguard Worker uint32_t mask = htonl(*naddr), host = ~mask;
321*cf5a6c84SAndroid Build Coastguard Worker if (host & (host + 1)) error_exit("invalid netmask");
322*cf5a6c84SAndroid Build Coastguard Worker for (plen = 0; mask; mask <<= 1) ++plen;
323*cf5a6c84SAndroid Build Coastguard Worker if (plen > 32) error_exit("invalid netmask");
324*cf5a6c84SAndroid Build Coastguard Worker }
325*cf5a6c84SAndroid Build Coastguard Worker }
326*cf5a6c84SAndroid Build Coastguard Worker netmask = plen;
327*cf5a6c84SAndroid Build Coastguard Worker rtMsg->rtm_dst_len = netmask;
328*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "gw")) {
329*cf5a6c84SAndroid Build Coastguard Worker if (!inet_pton(f, argv[1], &addr)) error_exit("invalid gw");
330*cf5a6c84SAndroid Build Coastguard Worker addAttr(nlMsg, sizeof(toybuf), &addr, RTA_GATEWAY, addr_len);
331*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "mss")) {
332*cf5a6c84SAndroid Build Coastguard Worker // TODO(emolitor): Add RTA_METRICS support
333*cf5a6c84SAndroid Build Coastguard Worker //set the TCP Maximum Segment Size for connections over this route.
334*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_mtu = atolx_range(argv[1], 64, 65536);
335*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_flags |= RTF_MSS;
336*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "window")) {
337*cf5a6c84SAndroid Build Coastguard Worker // TODO(emolitor): Add RTA_METRICS support
338*cf5a6c84SAndroid Build Coastguard Worker //set the TCP window size for connections over this route to W bytes.
339*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_window = atolx_range(argv[1], 128, INT_MAX); //win low
340*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_flags |= RTF_WINDOW;
341*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "irtt")) {
342*cf5a6c84SAndroid Build Coastguard Worker // TODO(emolitor): Add RTA_METRICS support
343*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_irtt = atolx_range(argv[1], 0, INT_MAX);
344*cf5a6c84SAndroid Build Coastguard Worker //rt->rt_flags |= RTF_IRTT;
345*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(*argv, "dev")) {
346*cf5a6c84SAndroid Build Coastguard Worker unsigned int if_idx = if_nametoindex(argv[1]);
347*cf5a6c84SAndroid Build Coastguard Worker if (!if_idx) perror_exit("dev");
348*cf5a6c84SAndroid Build Coastguard Worker addAttr(nlMsg, sizeof(toybuf), &if_idx, RTA_OIF, sizeof(unsigned int));
349*cf5a6c84SAndroid Build Coastguard Worker } else help_exit("no '%s'", *argv);
350*cf5a6c84SAndroid Build Coastguard Worker argv++;
351*cf5a6c84SAndroid Build Coastguard Worker }
352*cf5a6c84SAndroid Build Coastguard Worker }
353*cf5a6c84SAndroid Build Coastguard Worker
354*cf5a6c84SAndroid Build Coastguard Worker if (strcmp(tgtip, "default") != 0) {
355*cf5a6c84SAndroid Build Coastguard Worker char *prefix = strtok(0, "/");
356*cf5a6c84SAndroid Build Coastguard Worker
357*cf5a6c84SAndroid Build Coastguard Worker if (prefix) rtMsg->rtm_dst_len = strtoul(prefix, &prefix, 0);
358*cf5a6c84SAndroid Build Coastguard Worker if (!inet_pton(f, strtok(tgtip, "/"), &addr)) error_exit("invalid target");
359*cf5a6c84SAndroid Build Coastguard Worker addAttr(nlMsg, sizeof(toybuf), &addr, RTA_DST, addr_len);
360*cf5a6c84SAndroid Build Coastguard Worker } else rtMsg->rtm_dst_len = 0;
361*cf5a6c84SAndroid Build Coastguard Worker
362*cf5a6c84SAndroid Build Coastguard Worker xsend(sockfd, nlMsg, nlMsg->nlmsg_len);
363*cf5a6c84SAndroid Build Coastguard Worker xclose(sockfd);
364*cf5a6c84SAndroid Build Coastguard Worker }
365*cf5a6c84SAndroid Build Coastguard Worker
route_main(void)366*cf5a6c84SAndroid Build Coastguard Worker void route_main(void)
367*cf5a6c84SAndroid Build Coastguard Worker {
368*cf5a6c84SAndroid Build Coastguard Worker if (!*toys.optargs) {
369*cf5a6c84SAndroid Build Coastguard Worker if (!TT.A || !strcmp(TT.A, "inet")) display_routes(AF_INET);
370*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(TT.A, "inet6")) display_routes(AF_INET6);
371*cf5a6c84SAndroid Build Coastguard Worker else show_help(stdout, 1);
372*cf5a6c84SAndroid Build Coastguard Worker } else {
373*cf5a6c84SAndroid Build Coastguard Worker if (!TT.A) {
374*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc>1 && strchr(toys.optargs[1], ':')) {
375*cf5a6c84SAndroid Build Coastguard Worker xprintf("WARNING: Implicit IPV6 address using -Ainet6\n");
376*cf5a6c84SAndroid Build Coastguard Worker TT.A = "inet6";
377*cf5a6c84SAndroid Build Coastguard Worker } else TT.A = "inet";
378*cf5a6c84SAndroid Build Coastguard Worker }
379*cf5a6c84SAndroid Build Coastguard Worker
380*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(TT.A, "inet")) setroute(AF_INET, toys.optargs);
381*cf5a6c84SAndroid Build Coastguard Worker else setroute(AF_INET6, toys.optargs);
382*cf5a6c84SAndroid Build Coastguard Worker }
383*cf5a6c84SAndroid Build Coastguard Worker }
384