blob: 6a41b833189a011918098f85d2338cfe29e70c79 [file] [log] [blame]
Bernhard Reutner-Fischerd1d23a62006-01-12 12:08:46 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00002/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00004 *
Denys Vlasenkofb132e42010-10-29 11:46:52 +02005 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00006 *
7 * Changes:
8 *
Denys Vlasenkofb132e42010-10-29 11:46:52 +02009 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000010 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
11 */
12
Denys Vlasenkofb132e42010-10-29 11:46:52 +020013#include "ip_common.h" /* #include "libbb.h" is inside */
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020014#include "common_bufsiz.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000015#include "rt_names.h"
16#include "utils.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#ifndef RTAX_RTTVAR
19#define RTAX_RTTVAR RTAX_HOPS
20#endif
21
22
Denys Vlasenko36659fd2010-02-05 14:40:23 +010023struct filter_t {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000024 int tb;
Denis Vlasenko3e57adb2008-05-31 07:33:18 +000025 smallint flushed;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000026 char *flushb;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000027 int flushp;
28 int flushe;
29 struct rtnl_handle *rth;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010030 //int protocol, protocolmask; - write-only fields?!
André Draszik2f24d302017-06-13 19:59:59 +020031 int scope, scopemask;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010032 //int type; - read-only
33 //int typemask; - unused
34 //int tos, tosmask; - unused
Denys Vlasenkof1334712011-02-09 04:39:09 +010035 int iif;
36 int oif;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010037 //int realm, realmmask; - unused
38 //inet_prefix rprefsrc; - read-only
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000039 inet_prefix rvia;
40 inet_prefix rdst;
41 inet_prefix mdst;
42 inet_prefix rsrc;
43 inet_prefix msrc;
Denys Vlasenko36659fd2010-02-05 14:40:23 +010044} FIX_ALIASING;
45typedef struct filter_t filter_t;
Denis Vlasenko540a2a12007-04-07 01:14:45 +000046
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020047#define G_filter (*(filter_t*)bb_common_bufsiz1)
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +020048#define INIT_G() do { setup_common_bufsiz(); } while (0)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000049
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000050static int flush_update(void)
51{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010052 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
Denys Vlasenko651a2692010-03-23 16:25:17 +010053 bb_perror_msg("can't send flush request");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000054 return -1;
55 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010056 G_filter.flushp = 0;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000057 return 0;
58}
59
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020060static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000061 struct nlmsghdr *n, void *arg UNUSED_PARAM)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000062{
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000063 struct rtmsg *r = NLMSG_DATA(n);
64 int len = n->nlmsg_len;
Denys Vlasenko3bb235c2011-02-23 01:20:44 +010065 struct rtattr *tb[RTA_MAX+1];
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +000066 inet_prefix dst;
67 inet_prefix src;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000068 int host_len = -1;
Lukasz Nowakb42107f2016-12-13 12:58:31 +000069 uint32_t tid;
Eric Andersenc7bda1c2004-03-15 08:29:22 +000070
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000071 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
72 fprintf(stderr, "Not a route: %08x %08x %08x\n",
73 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
74 return 0;
75 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010076 if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000077 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000078 len -= NLMSG_LENGTH(sizeof(*r));
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +000079 if (len < 0)
80 bb_error_msg_and_die("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000081
Lukasz Nowakb42107f2016-12-13 12:58:31 +000082 memset(tb, 0, sizeof(tb));
83 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
84
85 if (tb[RTA_TABLE])
86 tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
87 else
88 tid = r->rtm_table;
89
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000090 if (r->rtm_family == AF_INET6)
91 host_len = 128;
92 else if (r->rtm_family == AF_INET)
93 host_len = 32;
94
95 if (r->rtm_family == AF_INET6) {
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010096 if (G_filter.tb) {
97 if (G_filter.tb < 0) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +000098 if (!(r->rtm_flags & RTM_F_CLONED)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000099 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000100 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000101 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000102 if (r->rtm_flags & RTM_F_CLONED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000103 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000104 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100105 if (G_filter.tb == RT_TABLE_LOCAL) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000106 if (r->rtm_type != RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000107 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000108 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100109 } else if (G_filter.tb == RT_TABLE_MAIN) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000110 if (r->rtm_type == RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000111 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000112 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000113 } else {
114 return 0;
115 }
116 }
117 }
118 } else {
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000119 if (G_filter.tb > 0 && G_filter.tb != tid) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000120 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000121 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000122 }
André Draszik2f24d302017-06-13 19:59:59 +0200123 if ((G_filter.scope ^ r->rtm_scope) & G_filter.scopemask)
124 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100125 if (G_filter.rdst.family
126 && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
127 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000128 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000129 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100130 if (G_filter.mdst.family
131 && (r->rtm_family != G_filter.mdst.family
132 || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
133 )
134 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000135 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000136 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100137 if (G_filter.rsrc.family
138 && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
139 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000140 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000141 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100142 if (G_filter.msrc.family
143 && (r->rtm_family != G_filter.msrc.family
144 || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
145 )
146 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000147 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000148 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000149
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100150 memset(&src, 0, sizeof(src));
151 memset(&dst, 0, sizeof(dst));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000152
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100153 if (tb[RTA_SRC]) {
154 src.bitlen = r->rtm_src_len;
155 src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
156 memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
157 }
158 if (tb[RTA_DST]) {
159 dst.bitlen = r->rtm_dst_len;
160 dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
161 memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
162 }
163
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100164 if (G_filter.rdst.family
165 && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
166 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000167 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100168 }
169 if (G_filter.mdst.family
170 && G_filter.mdst.bitlen >= 0
171 && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
172 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000173 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100174 }
175 if (G_filter.rsrc.family
176 && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
177 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000178 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100179 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100180 if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
181 && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
182 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000183 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100184 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100185 if (G_filter.oif != 0) {
186 if (!tb[RTA_OIF])
187 return 0;
188 if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
189 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100190 }
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000191
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100192 if (G_filter.flushb) {
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100193 struct nlmsghdr *fn;
194
Denys Vlasenkof1334712011-02-09 04:39:09 +0100195 /* We are creating route flush commands */
196
197 if (r->rtm_family == AF_INET6
198 && r->rtm_dst_len == 0
199 && r->rtm_type == RTN_UNREACHABLE
200 && tb[RTA_PRIORITY]
201 && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
202 ) {
203 return 0;
204 }
205
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100206 if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000207 if (flush_update())
Curt Brune69934702015-10-14 12:53:47 +0200208 xfunc_die();
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000209 }
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100210 fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000211 memcpy(fn, n, n->nlmsg_len);
212 fn->nlmsg_type = RTM_DELROUTE;
213 fn->nlmsg_flags = NLM_F_REQUEST;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100214 fn->nlmsg_seq = ++G_filter.rth->seq;
215 G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
216 G_filter.flushed = 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000217 return 0;
218 }
219
Denys Vlasenkof1334712011-02-09 04:39:09 +0100220 /* We are printing routes */
221
Glenn L McGrath16528552002-11-28 11:17:19 +0000222 if (n->nlmsg_type == RTM_DELROUTE) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000223 printf("Deleted ");
Glenn L McGrath16528552002-11-28 11:17:19 +0000224 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100225 if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
Denys Vlasenko3d8d5e82015-10-08 13:02:28 +0200226 printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
Glenn L McGrath16528552002-11-28 11:17:19 +0000227 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000228
229 if (tb[RTA_DST]) {
230 if (r->rtm_dst_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200231 printf("%s/%u ",
232 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
233 r->rtm_dst_len
234 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000235 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000236 printf("%s ", format_host(r->rtm_family,
237 RTA_PAYLOAD(tb[RTA_DST]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200238 RTA_DATA(tb[RTA_DST]))
239 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000240 }
241 } else if (r->rtm_dst_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000242 printf("0/%d ", r->rtm_dst_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000243 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000244 printf("default ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000245 }
246 if (tb[RTA_SRC]) {
247 if (r->rtm_src_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200248 printf("from %s/%u ",
249 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
250 r->rtm_src_len
251 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000252 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000253 printf("from %s ", format_host(r->rtm_family,
254 RTA_PAYLOAD(tb[RTA_SRC]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200255 RTA_DATA(tb[RTA_SRC]))
256 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000257 }
258 } else if (r->rtm_src_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000259 printf("from 0/%u ", r->rtm_src_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000260 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100261 if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000262 printf("via %s ", format_host(r->rtm_family,
263 RTA_PAYLOAD(tb[RTA_GATEWAY]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200264 RTA_DATA(tb[RTA_GATEWAY]))
265 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000266 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100267 if (tb[RTA_OIF]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000268 printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
Glenn L McGrath16528552002-11-28 11:17:19 +0000269 }
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000270#if ENABLE_FEATURE_IP_RULE
271 if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
272 printf("table %s ", rtnl_rttable_n2a(tid));
273#endif
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000274
André Draszik2f24d302017-06-13 19:59:59 +0200275 /* Todo: parse & show "proto kernel" here */
276 if (!(r->rtm_flags & RTM_F_CLONED)) {
277 if ((r->rtm_scope != RT_SCOPE_UNIVERSE) && G_filter.scopemask != -1)
278 printf("scope %s ", rtnl_rtscope_n2a(r->rtm_scope));
279 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100280
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100281 if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000282 /* Do not use format_host(). It is our local addr
283 and symbolic name will not be useful.
284 */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000285 printf(" src %s ", rt_addr_n2a(r->rtm_family,
Denys Vlasenko926d8012015-10-14 13:56:42 +0200286 RTA_DATA(tb[RTA_PREFSRC])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000287 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000288 if (tb[RTA_PRIORITY]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000289 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
Glenn L McGrath16528552002-11-28 11:17:19 +0000290 }
Michael Tokarev1a114392014-07-28 10:05:41 +0400291 if (r->rtm_flags & RTNH_F_DEAD) {
292 printf("dead ");
293 }
294 if (r->rtm_flags & RTNH_F_ONLINK) {
295 printf("onlink ");
296 }
297 if (r->rtm_flags & RTNH_F_PERVASIVE) {
298 printf("pervasive ");
299 }
300 if (r->rtm_flags & RTM_F_NOTIFY) {
301 printf("notify ");
302 }
303
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000304 if (r->rtm_family == AF_INET6) {
305 struct rta_cacheinfo *ci = NULL;
Glenn L McGrath16528552002-11-28 11:17:19 +0000306 if (tb[RTA_CACHEINFO]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000307 ci = RTA_DATA(tb[RTA_CACHEINFO]);
Glenn L McGrath16528552002-11-28 11:17:19 +0000308 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000309 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000310 if (r->rtm_flags & RTM_F_CLONED) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000311 printf("%c cache ", _SL_);
Glenn L McGrath16528552002-11-28 11:17:19 +0000312 }
313 if (ci->rta_expires) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000314 printf(" expires %dsec", ci->rta_expires / get_hz());
Glenn L McGrath16528552002-11-28 11:17:19 +0000315 }
316 if (ci->rta_error != 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000317 printf(" error %d", ci->rta_error);
Glenn L McGrath16528552002-11-28 11:17:19 +0000318 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000319 } else if (ci) {
320 if (ci->rta_error != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000321 printf(" error %d", ci->rta_error);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000322 }
323 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100324 if (tb[RTA_IIF] && G_filter.iif == 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000325 printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000326 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000327 bb_putchar('\n');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000328 return 0;
329}
330
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200331static int str_is_lock(const char *str)
332{
333 return strcmp(str, "lock") == 0;
334}
335
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000336/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000337static int iproute_modify(int cmd, unsigned flags, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000338{
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200339 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000340 static const char keywords[] ALIGN1 =
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200341 "src\0""via\0"
342 "mtu\0""advmss\0"
343 "scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
Michael Tokarev1a114392014-07-28 10:05:41 +0400344 "dev\0""oif\0""to\0""metric\0""onlink\0";
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200345#define keyword_via (keywords + sizeof("src"))
346#define keyword_mtu (keyword_via + sizeof("via"))
347#define keyword_advmss (keyword_mtu + sizeof("mtu"))
348#define keyword_scope (keyword_advmss + sizeof("advmss"))
349#define keyword_proto (keyword_scope + sizeof("scope"))
350#define keyword_table (keyword_proto + sizeof("protocol"))
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000351 enum {
352 ARG_src,
353 ARG_via,
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200354 ARG_mtu,
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200355 ARG_advmss,
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100356 ARG_scope,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000357 ARG_protocol,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000358IF_FEATURE_IP_RULE(ARG_table,)
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000359 ARG_dev,
360 ARG_oif,
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000361 ARG_to,
362 ARG_metric,
Michael Tokarev1a114392014-07-28 10:05:41 +0400363 ARG_onlink,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000364 };
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000365 enum {
366 gw_ok = 1 << 0,
367 dst_ok = 1 << 1,
368 proto_ok = 1 << 2,
369 type_ok = 1 << 3
370 };
371 struct rtnl_handle rth;
372 struct {
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200373 struct nlmsghdr n;
374 struct rtmsg r;
375 char buf[1024];
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000376 } req;
377 char mxbuf[256];
378 struct rtattr * mxrta = (void*)mxbuf;
379 unsigned mxlock = 0;
380 char *d = NULL;
381 smalluint ok = 0;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100382 smalluint scope_ok = 0;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000383 int arg;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000384
385 memset(&req, 0, sizeof(req));
386
387 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000388 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000389 req.n.nlmsg_type = cmd;
390 req.r.rtm_family = preferred_family;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100391 if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000392 req.r.rtm_table = RT_TABLE_MAIN;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100393 if (RT_SCOPE_NOWHERE != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000394 req.r.rtm_scope = RT_SCOPE_NOWHERE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000395
396 if (cmd != RTM_DELROUTE) {
Denys Vlasenko34ecc3b2016-08-14 01:30:34 +0200397 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100398 if (RTPROT_BOOT != 0)
399 req.r.rtm_protocol = RTPROT_BOOT;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100400 if (RTN_UNICAST != 0)
401 req.r.rtm_type = RTN_UNICAST;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000402 }
403
404 mxrta->rta_type = RTA_METRICS;
405 mxrta->rta_len = RTA_LENGTH(0);
406
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000407 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000408 arg = index_in_substrings(keywords, *argv);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000409 if (arg == ARG_src) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000410 inet_prefix addr;
411 NEXT_ARG();
412 get_addr(&addr, *argv, req.r.rtm_family);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000413 if (req.r.rtm_family == AF_UNSPEC)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000414 req.r.rtm_family = addr.family;
415 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000416 } else if (arg == ARG_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000417 inet_prefix addr;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000418 ok |= gw_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000419 NEXT_ARG();
420 get_addr(&addr, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000421 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000422 req.r.rtm_family = addr.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000423 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000424 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000425 } else if (arg == ARG_mtu) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000426 unsigned mtu;
427 NEXT_ARG();
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200428 if (str_is_lock(*argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000429 mxlock |= (1 << RTAX_MTU);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000430 NEXT_ARG();
431 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200432 mtu = get_unsigned(*argv, keyword_mtu);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000433 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200434 } else if (arg == ARG_advmss) {
435 unsigned mss;
436 NEXT_ARG();
437 if (str_is_lock(*argv)) {
438 mxlock |= (1 << RTAX_ADVMSS);
439 NEXT_ARG();
440 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200441 mss = get_unsigned(*argv, keyword_advmss);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200442 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100443 } else if (arg == ARG_scope) {
444 uint32_t scope;
445 NEXT_ARG();
446 if (rtnl_rtscope_a2n(&scope, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200447 invarg_1_to_2(*argv, keyword_scope);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100448 req.r.rtm_scope = scope;
449 scope_ok = 1;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000450 } else if (arg == ARG_protocol) {
Eric Andersend78aea82006-01-30 18:00:02 +0000451 uint32_t prot;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000452 NEXT_ARG();
453 if (rtnl_rtprot_a2n(&prot, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200454 invarg_1_to_2(*argv, keyword_proto);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000455 req.r.rtm_protocol = prot;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000456 ok |= proto_ok;
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000457#if ENABLE_FEATURE_IP_RULE
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000458 } else if (arg == ARG_table) {
Denis Vlasenkocda6c632006-12-15 00:59:35 +0000459 uint32_t tid;
460 NEXT_ARG();
461 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200462 invarg_1_to_2(*argv, keyword_table);
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000463 if (tid < 256)
464 req.r.rtm_table = tid;
465 else {
466 req.r.rtm_table = RT_TABLE_UNSPEC;
467 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
468 }
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000469#endif
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000470 } else if (arg == ARG_dev || arg == ARG_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000471 NEXT_ARG();
472 d = *argv;
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000473 } else if (arg == ARG_metric) {
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200474//TODO: "metric", "priority" and "preference" are synonyms
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000475 uint32_t metric;
476 NEXT_ARG();
Denis Vlasenko76140a72009-03-05 09:21:57 +0000477 metric = get_u32(*argv, "metric");
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000478 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
Michael Tokarev1a114392014-07-28 10:05:41 +0400479 } else if (arg == ARG_onlink) {
480 req.r.rtm_flags |= RTNH_F_ONLINK;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000481 } else {
482 int type;
483 inet_prefix dst;
484
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000485 if (arg == ARG_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000486 NEXT_ARG();
487 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000488 if ((**argv < '0' || **argv > '9')
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100489 && rtnl_rtntype_a2n(&type, *argv) == 0
490 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000491 NEXT_ARG();
492 req.r.rtm_type = type;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000493 ok |= type_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000494 }
495
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000496 if (ok & dst_ok) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000497 duparg2("to", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000498 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000499 get_prefix(&dst, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000500 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000501 req.r.rtm_family = dst.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000502 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000503 req.r.rtm_dst_len = dst.bitlen;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000504 ok |= dst_ok;
Glenn L McGrath16528552002-11-28 11:17:19 +0000505 if (dst.bytelen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000506 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
Glenn L McGrath16528552002-11-28 11:17:19 +0000507 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000508 }
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200509/* Other keywords recognized by iproute2-3.19.0: */
510#if 0
511 } else if (strcmp(*argv, "from") == 0) {
512 inet_prefix addr;
513 NEXT_ARG();
514 get_prefix(&addr, *argv, req.r.rtm_family);
515 if (req.r.rtm_family == AF_UNSPEC)
516 req.r.rtm_family = addr.family;
517 if (addr.bytelen)
518 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
519 req.r.rtm_src_len = addr.bitlen;
520 } else if (strcmp(*argv, "tos") == 0 ||
521 matches(*argv, "dsfield") == 0) {
522 __u32 tos;
523 NEXT_ARG();
524 if (rtnl_dsfield_a2n(&tos, *argv))
525 invarg("\"tos\" value is invalid\n", *argv);
526 req.r.rtm_tos = tos;
527 } else if (strcmp(*argv, "hoplimit") == 0) {
528 unsigned hoplimit;
529 NEXT_ARG();
530 if (strcmp(*argv, "lock") == 0) {
531 mxlock |= (1<<RTAX_HOPLIMIT);
532 NEXT_ARG();
533 }
534 if (get_unsigned(&hoplimit, *argv, 0))
535 invarg("\"hoplimit\" value is invalid\n", *argv);
536 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200537 } else if (matches(*argv, "reordering") == 0) {
538 unsigned reord;
539 NEXT_ARG();
540 if (strcmp(*argv, "lock") == 0) {
541 mxlock |= (1<<RTAX_REORDERING);
542 NEXT_ARG();
543 }
544 if (get_unsigned(&reord, *argv, 0))
545 invarg("\"reordering\" value is invalid\n", *argv);
546 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
547 } else if (strcmp(*argv, "rtt") == 0) {
548 unsigned rtt;
549 NEXT_ARG();
550 if (strcmp(*argv, "lock") == 0) {
551 mxlock |= (1<<RTAX_RTT);
552 NEXT_ARG();
553 }
554 if (get_time_rtt(&rtt, *argv, &raw))
555 invarg("\"rtt\" value is invalid\n", *argv);
556 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
557 (raw) ? rtt : rtt * 8);
558 } else if (strcmp(*argv, "rto_min") == 0) {
559 unsigned rto_min;
560 NEXT_ARG();
561 mxlock |= (1<<RTAX_RTO_MIN);
562 if (get_time_rtt(&rto_min, *argv, &raw))
563 invarg("\"rto_min\" value is invalid\n",
564 *argv);
565 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
566 rto_min);
567 } else if (matches(*argv, "window") == 0) {
568 unsigned win;
569 NEXT_ARG();
570 if (strcmp(*argv, "lock") == 0) {
571 mxlock |= (1<<RTAX_WINDOW);
572 NEXT_ARG();
573 }
574 if (get_unsigned(&win, *argv, 0))
575 invarg("\"window\" value is invalid\n", *argv);
576 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
577 } else if (matches(*argv, "cwnd") == 0) {
578 unsigned win;
579 NEXT_ARG();
580 if (strcmp(*argv, "lock") == 0) {
581 mxlock |= (1<<RTAX_CWND);
582 NEXT_ARG();
583 }
584 if (get_unsigned(&win, *argv, 0))
585 invarg("\"cwnd\" value is invalid\n", *argv);
586 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
587 } else if (matches(*argv, "initcwnd") == 0) {
588 unsigned win;
589 NEXT_ARG();
590 if (strcmp(*argv, "lock") == 0) {
591 mxlock |= (1<<RTAX_INITCWND);
592 NEXT_ARG();
593 }
594 if (get_unsigned(&win, *argv, 0))
595 invarg("\"initcwnd\" value is invalid\n", *argv);
596 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
597 } else if (matches(*argv, "initrwnd") == 0) {
598 unsigned win;
599 NEXT_ARG();
600 if (strcmp(*argv, "lock") == 0) {
601 mxlock |= (1<<RTAX_INITRWND);
602 NEXT_ARG();
603 }
604 if (get_unsigned(&win, *argv, 0))
605 invarg("\"initrwnd\" value is invalid\n", *argv);
606 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
607 } else if (matches(*argv, "features") == 0) {
608 unsigned int features = 0;
609
610 while (argc > 0) {
611 NEXT_ARG();
612
613 if (strcmp(*argv, "ecn") == 0)
614 features |= RTAX_FEATURE_ECN;
615 else
616 invarg("\"features\" value not valid\n", *argv);
617 break;
618 }
619
620 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features);
621 } else if (matches(*argv, "quickack") == 0) {
622 unsigned quickack;
623 NEXT_ARG();
624 if (get_unsigned(&quickack, *argv, 0))
625 invarg("\"quickack\" value is invalid\n", *argv);
626 if (quickack != 1 && quickack != 0)
627 invarg("\"quickack\" value should be 0 or 1\n", *argv);
628 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
629 } else if (matches(*argv, "rttvar") == 0) {
630 unsigned win;
631 NEXT_ARG();
632 if (strcmp(*argv, "lock") == 0) {
633 mxlock |= (1<<RTAX_RTTVAR);
634 NEXT_ARG();
635 }
636 if (get_time_rtt(&win, *argv, &raw))
637 invarg("\"rttvar\" value is invalid\n", *argv);
638 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
639 (raw) ? win : win * 4);
640 } else if (matches(*argv, "ssthresh") == 0) {
641 unsigned win;
642 NEXT_ARG();
643 if (strcmp(*argv, "lock") == 0) {
644 mxlock |= (1<<RTAX_SSTHRESH);
645 NEXT_ARG();
646 }
647 if (get_unsigned(&win, *argv, 0))
648 invarg("\"ssthresh\" value is invalid\n", *argv);
649 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
650 } else if (matches(*argv, "realms") == 0) {
651 __u32 realm;
652 NEXT_ARG();
653 if (get_rt_realms(&realm, *argv))
654 invarg("\"realm\" value is invalid\n", *argv);
655 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
656 } else if (strcmp(*argv, "nexthop") == 0) {
657 nhs_ok = 1;
658 break;
659 }
660#endif
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000661 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000662 }
663
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000664 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000665
Eric Andersen5780adb2002-11-15 09:12:47 +0000666 if (d) {
667 int idx;
668
669 ll_init_map(&rth);
670
671 if (d) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000672 idx = xll_name_to_index(d);
Eric Andersen5780adb2002-11-15 09:12:47 +0000673 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
674 }
675 }
676
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000677 if (mxrta->rta_len > RTA_LENGTH(0)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000678 if (mxlock) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000679 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
Glenn L McGrath16528552002-11-28 11:17:19 +0000680 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000681 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
682 }
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000683
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100684 if (!scope_ok) {
685 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
686 req.r.rtm_scope = RT_SCOPE_HOST;
687 else
688 if (req.r.rtm_type == RTN_BROADCAST
689 || req.r.rtm_type == RTN_MULTICAST
690 || req.r.rtm_type == RTN_ANYCAST
691 ) {
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000692 req.r.rtm_scope = RT_SCOPE_LINK;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100693 }
694 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
695 if (cmd == RTM_DELROUTE)
696 req.r.rtm_scope = RT_SCOPE_NOWHERE;
697 else if (!(ok & gw_ok))
698 req.r.rtm_scope = RT_SCOPE_LINK;
699 }
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000700 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000701
Glenn L McGrath16528552002-11-28 11:17:19 +0000702 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000703 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000704 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000705
Glenn L McGrath16528552002-11-28 11:17:19 +0000706 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000707 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +0000708 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000709
710 return 0;
711}
712
713static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
714{
715 struct {
716 struct nlmsghdr nlh;
717 struct rtmsg rtm;
718 } req;
719 struct sockaddr_nl nladdr;
720
721 memset(&nladdr, 0, sizeof(nladdr));
722 memset(&req, 0, sizeof(req));
723 nladdr.nl_family = AF_NETLINK;
724
725 req.nlh.nlmsg_len = sizeof(req);
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000726 if (RTM_GETROUTE)
727 req.nlh.nlmsg_type = RTM_GETROUTE;
728 if (NLM_F_ROOT | NLM_F_REQUEST)
729 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
730 /*req.nlh.nlmsg_pid = 0; - memset did it already */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000731 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
732 req.rtm.rtm_family = family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000733 if (RTM_F_CLONED)
734 req.rtm.rtm_flags = RTM_F_CLONED;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000735
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000736 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000737}
738
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000739static void iproute_flush_cache(void)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000740{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000741 static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000742 int flush_fd = open_or_warn(fn, O_WRONLY);
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000743
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000744 if (flush_fd < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000745 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000746 }
747
Denis Vlasenko89ef65f2007-01-29 23:43:18 +0000748 if (write(flush_fd, "-1", 2) < 2) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100749 bb_perror_msg("can't flush routing cache");
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000750 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000751 }
752 close(flush_fd);
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000753}
754
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000755static void iproute_reset_filter(void)
756{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100757 memset(&G_filter, 0, sizeof(G_filter));
758 G_filter.mdst.bitlen = -1;
759 G_filter.msrc.bitlen = -1;
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000760}
761
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000762/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000763static int iproute_list_or_flush(char **argv, int flush)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000764{
765 int do_ipv6 = preferred_family;
766 struct rtnl_handle rth;
767 char *id = NULL;
768 char *od = NULL;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000769 static const char keywords[] ALIGN1 =
André Draszik2f24d302017-06-13 19:59:59 +0200770 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000771 /* "ip route list/flush" parameters: */
772 "protocol\0" "dev\0" "oif\0" "iif\0"
773 "via\0" "table\0" "cache\0"
André Draszik2f24d302017-06-13 19:59:59 +0200774 "from\0" "to\0" "scope\0"
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000775 /* and possible further keywords */
776 "all\0"
777 "root\0"
778 "match\0"
779 "exact\0"
780 "main\0"
781 ;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000782 enum {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000783 KW_proto, KW_dev, KW_oif, KW_iif,
784 KW_via, KW_table, KW_cache,
André Draszik2f24d302017-06-13 19:59:59 +0200785 KW_from, KW_to, KW_scope,
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000786 /* */
787 KW_all,
788 KW_root,
789 KW_match,
790 KW_exact,
791 KW_main,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000792 };
793 int arg, parm;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000794
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000795 iproute_reset_filter();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100796 G_filter.tb = RT_TABLE_MAIN;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000797
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000798 if (flush && !*argv)
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000799 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000800
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000801 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000802 arg = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000803 if (arg == KW_proto) {
Eric Andersend78aea82006-01-30 18:00:02 +0000804 uint32_t prot = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000805 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100806 //G_filter.protocolmask = -1;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000807 if (rtnl_rtprot_a2n(&prot, *argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000808 if (index_in_strings(keywords, *argv) != KW_all)
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200809 invarg_1_to_2(*argv, "protocol");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000810 prot = 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100811 //G_filter.protocolmask = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000812 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100813 //G_filter.protocol = prot;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000814 } else if (arg == KW_dev || arg == KW_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000815 NEXT_ARG();
816 od = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000817 } else if (arg == KW_iif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000818 NEXT_ARG();
819 id = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000820 } else if (arg == KW_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000821 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100822 get_prefix(&G_filter.rvia, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000823 } else if (arg == KW_table) { /* table all/cache/main */
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000824 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000825 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000826 if (parm == KW_cache)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100827 G_filter.tb = -1;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000828 else if (parm == KW_all)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100829 G_filter.tb = 0;
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000830 else if (parm != KW_main) {
831#if ENABLE_FEATURE_IP_RULE
832 uint32_t tid;
833 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200834 invarg_1_to_2(*argv, "table");
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100835 G_filter.tb = tid;
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000836#else
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200837 invarg_1_to_2(*argv, "table");
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000838#endif
839 }
Denis Vlasenko79c69042007-11-27 09:42:33 +0000840 } else if (arg == KW_cache) {
841 /* The command 'ip route flush cache' is used by OpenSWAN.
842 * Assuming it's a synonym for 'ip route flush table cache' */
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100843 G_filter.tb = -1;
André Draszik2f24d302017-06-13 19:59:59 +0200844 } else if (arg == KW_scope) {
845 uint32_t scope;
846 NEXT_ARG();
847 G_filter.scopemask = -1;
848 if (rtnl_rtscope_a2n(&scope, *argv)) {
849 if (strcmp(*argv, "all") != 0)
850 invarg_1_to_2(*argv, "scope");
851 scope = RT_SCOPE_NOWHERE;
852 G_filter.scopemask = 0;
853 }
854 G_filter.scope = scope;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000855 } else if (arg == KW_from) {
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000856 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000857 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000858 if (parm == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000859 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100860 get_prefix(&G_filter.rsrc, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000861 } else if (parm == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000862 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100863 get_prefix(&G_filter.msrc, *argv, do_ipv6);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000864 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000865 if (parm == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000866 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100867 get_prefix(&G_filter.msrc, *argv, do_ipv6);
868 G_filter.rsrc = G_filter.msrc;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000869 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000870 } else { /* "to" is the default parameter */
871 if (arg == KW_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000872 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000873 arg = index_in_substrings(keywords, *argv);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000874 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000875 /* parm = arg; - would be more plausible, but we reuse 'arg' here */
876 if (arg == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000877 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100878 get_prefix(&G_filter.rdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000879 } else if (arg == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000880 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100881 get_prefix(&G_filter.mdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000882 } else { /* "to exact" is the default */
883 if (arg == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000884 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100885 get_prefix(&G_filter.mdst, *argv, do_ipv6);
886 G_filter.rdst = G_filter.mdst;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000887 }
888 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000889 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000890 }
891
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100892 if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000893 do_ipv6 = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000894 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000895
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000896 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000897 ll_init_map(&rth);
898
899 if (id || od) {
900 int idx;
901
902 if (id) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000903 idx = xll_name_to_index(id);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100904 G_filter.iif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000905 }
906 if (od) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000907 idx = xll_name_to_index(od);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100908 G_filter.oif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000909 }
910 }
911
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000912 if (flush) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000913 char flushb[4096-512];
914
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100915 if (G_filter.tb == -1) { /* "flush table cache" */
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000916 if (do_ipv6 != AF_INET6)
917 iproute_flush_cache();
918 if (do_ipv6 == AF_INET)
919 return 0;
920 }
921
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100922 G_filter.flushb = flushb;
923 G_filter.flushp = 0;
924 G_filter.flushe = sizeof(flushb);
925 G_filter.rth = &rth;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000926
927 for (;;) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000928 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100929 G_filter.flushed = 0;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000930 xrtnl_dump_filter(&rth, print_route, NULL);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100931 if (G_filter.flushed == 0)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000932 return 0;
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000933 if (flush_update())
934 return 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000935 }
936 }
937
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100938 if (G_filter.tb != -1) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000939 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000940 } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100941 bb_perror_msg_and_die("can't send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000942 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000943 xrtnl_dump_filter(&rth, print_route, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000944
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000945 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000946}
947
948
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000949/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000950static int iproute_get(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000951{
952 struct rtnl_handle rth;
953 struct {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000954 struct nlmsghdr n;
955 struct rtmsg r;
956 char buf[1024];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000957 } req;
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000958 char *idev = NULL;
959 char *odev = NULL;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000960 bool connected = 0;
961 bool from_ok = 0;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000962 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000963 "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000964
965 memset(&req, 0, sizeof(req));
966
967 iproute_reset_filter();
968
969 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000970 if (NLM_F_REQUEST)
971 req.n.nlmsg_flags = NLM_F_REQUEST;
972 if (RTM_GETROUTE)
973 req.n.nlmsg_type = RTM_GETROUTE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000974 req.r.rtm_family = preferred_family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000975 /*req.r.rtm_table = 0; - memset did this already */
976 /*req.r.rtm_protocol = 0;*/
977 /*req.r.rtm_scope = 0;*/
978 /*req.r.rtm_type = 0;*/
979 /*req.r.rtm_src_len = 0;*/
980 /*req.r.rtm_dst_len = 0;*/
981 /*req.r.rtm_tos = 0;*/
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000982
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000983 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000984 switch (index_in_strings(options, *argv)) {
Glenn L McGrath18eae002002-12-02 00:54:10 +0000985 case 0: /* from */
986 {
987 inet_prefix addr;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000988 NEXT_ARG();
Glenn L McGrath18eae002002-12-02 00:54:10 +0000989 from_ok = 1;
990 get_prefix(&addr, *argv, req.r.rtm_family);
991 if (req.r.rtm_family == AF_UNSPEC) {
992 req.r.rtm_family = addr.family;
993 }
994 if (addr.bytelen) {
995 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
996 }
997 req.r.rtm_src_len = addr.bitlen;
998 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000999 }
Glenn L McGrath18eae002002-12-02 00:54:10 +00001000 case 1: /* iif */
1001 NEXT_ARG();
1002 idev = *argv;
1003 break;
1004 case 2: /* oif */
1005 case 3: /* dev */
1006 NEXT_ARG();
1007 odev = *argv;
1008 break;
1009 case 4: /* notify */
1010 req.r.rtm_flags |= RTM_F_NOTIFY;
1011 break;
1012 case 5: /* connected */
1013 connected = 1;
1014 break;
1015 case 6: /* to */
1016 NEXT_ARG();
1017 default:
1018 {
1019 inet_prefix addr;
1020 get_prefix(&addr, *argv, req.r.rtm_family);
1021 if (req.r.rtm_family == AF_UNSPEC) {
1022 req.r.rtm_family = addr.family;
1023 }
1024 if (addr.bytelen) {
1025 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
1026 }
1027 req.r.rtm_dst_len = addr.bitlen;
1028 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001029 }
Christian Hornung3bbfb582010-11-03 14:08:00 +01001030 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001031 }
1032
1033 if (req.r.rtm_dst_len == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001034 bb_error_msg_and_die("need at least destination address");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001035 }
1036
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001037 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001038
1039 ll_init_map(&rth);
1040
1041 if (idev || odev) {
1042 int idx;
1043
1044 if (idev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001045 idx = xll_name_to_index(idev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001046 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1047 }
1048 if (odev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001049 idx = xll_name_to_index(odev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001050 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1051 }
1052 }
1053
Glenn L McGrath16528552002-11-28 11:17:19 +00001054 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001055 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +00001056 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001057
Glenn L McGrath16528552002-11-28 11:17:19 +00001058 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001059 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001060 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001061
1062 if (connected && !from_ok) {
1063 struct rtmsg *r = NLMSG_DATA(&req.n);
1064 int len = req.n.nlmsg_len;
1065 struct rtattr * tb[RTA_MAX+1];
1066
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001067 print_route(NULL, &req.n, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001068
1069 if (req.n.nlmsg_type != RTM_NEWROUTE) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001070 bb_error_msg_and_die("not a route?");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001071 }
1072 len -= NLMSG_LENGTH(sizeof(*r));
1073 if (len < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001074 bb_error_msg_and_die("wrong len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001075 }
1076
1077 memset(tb, 0, sizeof(tb));
1078 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1079
1080 if (tb[RTA_PREFSRC]) {
1081 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1082 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1083 } else if (!tb[RTA_SRC]) {
Denys Vlasenko651a2692010-03-23 16:25:17 +01001084 bb_error_msg_and_die("can't connect the route");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001085 }
Glenn L McGrath16528552002-11-28 11:17:19 +00001086 if (!odev && tb[RTA_OIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001087 tb[RTA_OIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001088 }
1089 if (tb[RTA_GATEWAY]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001090 tb[RTA_GATEWAY]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001091 }
1092 if (!idev && tb[RTA_IIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001093 tb[RTA_IIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001094 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001095 req.n.nlmsg_flags = NLM_F_REQUEST;
1096 req.n.nlmsg_type = RTM_GETROUTE;
1097
Glenn L McGrath16528552002-11-28 11:17:19 +00001098 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001099 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001100 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001101 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001102 print_route(NULL, &req.n, NULL);
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001103 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001104}
1105
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001106/* Return value becomes exitcode. It's okay to not return at all */
Denys Vlasenko2e9b5512010-07-24 23:27:38 +02001107int FAST_FUNC do_iproute(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001108{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001109 static const char ip_route_commands[] ALIGN1 =
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001110 "a\0""add\0""append\0""change\0""chg\0"
1111 "delete\0""get\0""list\0""show\0"
1112 "prepend\0""replace\0""test\0""flush\0"
1113 ;
1114 enum {
1115 CMD_a = 0, CMD_add, CMD_append, CMD_change, CMD_chg,
1116 CMD_delete, CMD_get, CMD_list, CMD_show,
1117 CMD_prepend, CMD_replace, CMD_test, CMD_flush,
1118 };
Denis Vlasenko83c44222008-01-04 15:28:28 +00001119 int command_num;
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001120 unsigned flags = 0;
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001121 int cmd = RTM_NEWROUTE;
1122
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +02001123 INIT_G();
1124
Denis Vlasenko83c44222008-01-04 15:28:28 +00001125 if (!*argv)
1126 return iproute_list_or_flush(argv, 0);
1127
Denis Vlasenko5af906e2006-11-05 18:05:09 +00001128 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
1129 /* It probably means that it is using "first match" rule */
Denis Vlasenko83c44222008-01-04 15:28:28 +00001130 command_num = index_in_substrings(ip_route_commands, *argv);
1131
Denis Vlasenkoc16bd212006-09-27 19:51:06 +00001132 switch (command_num) {
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001133 case CMD_a:
1134 case CMD_add:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001135 flags = NLM_F_CREATE|NLM_F_EXCL;
1136 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001137 case CMD_append:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001138 flags = NLM_F_CREATE|NLM_F_APPEND;
1139 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001140 case CMD_change:
1141 case CMD_chg:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001142 flags = NLM_F_REPLACE;
1143 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001144 case CMD_delete:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001145 cmd = RTM_DELROUTE;
1146 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001147 case CMD_get:
1148 return iproute_get(argv + 1);
1149 case CMD_list:
1150 case CMD_show:
1151 return iproute_list_or_flush(argv + 1, 0);
1152 case CMD_prepend:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001153 flags = NLM_F_CREATE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001154 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001155 case CMD_replace:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001156 flags = NLM_F_CREATE|NLM_F_REPLACE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001157 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001158 case CMD_test:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001159 flags = NLM_F_EXCL;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001160 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001161 case CMD_flush:
1162 return iproute_list_or_flush(argv + 1, 1);
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001163 default:
Denys Vlasenko0f296a32015-10-14 13:21:01 +02001164 invarg_1_to_2(*argv, applet_name);
Glenn L McGrath16528552002-11-28 11:17:19 +00001165 }
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001166
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001167 return iproute_modify(cmd, flags, argv + 1);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001168}