blob: e8b26cb2f59fa540beb8c9d404b3a04af2e6dc9d [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 */
Denys Vlasenkofb132e42010-10-29 11:46:52 +020012#include "ip_common.h" /* #include "libbb.h" is inside */
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020013#include "common_bufsiz.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000014#include "rt_names.h"
15#include "utils.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000016
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017#ifndef RTAX_RTTVAR
18#define RTAX_RTTVAR RTAX_HOPS
19#endif
20
21
Denys Vlasenko36659fd2010-02-05 14:40:23 +010022struct filter_t {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000023 int tb;
Denis Vlasenko3e57adb2008-05-31 07:33:18 +000024 smallint flushed;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000025 char *flushb;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000026 int flushp;
27 int flushe;
28 struct rtnl_handle *rth;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010029 //int protocol, protocolmask; - write-only fields?!
André Draszik2f24d302017-06-13 19:59:59 +020030 int scope, scopemask;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010031 //int type; - read-only
32 //int typemask; - unused
33 //int tos, tosmask; - unused
Denys Vlasenkof1334712011-02-09 04:39:09 +010034 int iif;
35 int oif;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010036 //int realm, realmmask; - unused
37 //inet_prefix rprefsrc; - read-only
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000038 inet_prefix rvia;
39 inet_prefix rdst;
40 inet_prefix mdst;
41 inet_prefix rsrc;
42 inet_prefix msrc;
Denys Vlasenko36659fd2010-02-05 14:40:23 +010043} FIX_ALIASING;
44typedef struct filter_t filter_t;
Denis Vlasenko540a2a12007-04-07 01:14:45 +000045
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020046#define G_filter (*(filter_t*)bb_common_bufsiz1)
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +020047#define INIT_G() do { setup_common_bufsiz(); } while (0)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000048
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000049static int flush_update(void)
50{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010051 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
Denys Vlasenko651a2692010-03-23 16:25:17 +010052 bb_perror_msg("can't send flush request");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000053 return -1;
54 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010055 G_filter.flushp = 0;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000056 return 0;
57}
58
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020059static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000060 struct nlmsghdr *n, void *arg UNUSED_PARAM)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000061{
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000062 struct rtmsg *r = NLMSG_DATA(n);
63 int len = n->nlmsg_len;
Denys Vlasenko3bb235c2011-02-23 01:20:44 +010064 struct rtattr *tb[RTA_MAX+1];
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +000065 inet_prefix dst;
66 inet_prefix src;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000067 int host_len = -1;
Lukasz Nowakb42107f2016-12-13 12:58:31 +000068 uint32_t tid;
Eric Andersenc7bda1c2004-03-15 08:29:22 +000069
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000070 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
71 fprintf(stderr, "Not a route: %08x %08x %08x\n",
72 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
73 return 0;
74 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010075 if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000076 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000077 len -= NLMSG_LENGTH(sizeof(*r));
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +000078 if (len < 0)
79 bb_error_msg_and_die("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000080
Lukasz Nowakb42107f2016-12-13 12:58:31 +000081 memset(tb, 0, sizeof(tb));
82 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
83
84 if (tb[RTA_TABLE])
85 tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
86 else
87 tid = r->rtm_table;
88
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000089 if (r->rtm_family == AF_INET6)
90 host_len = 128;
91 else if (r->rtm_family == AF_INET)
92 host_len = 32;
93
94 if (r->rtm_family == AF_INET6) {
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010095 if (G_filter.tb) {
96 if (G_filter.tb < 0) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +000097 if (!(r->rtm_flags & RTM_F_CLONED)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000098 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +000099 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000100 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000101 if (r->rtm_flags & RTM_F_CLONED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000102 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000103 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100104 if (G_filter.tb == RT_TABLE_LOCAL) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000105 if (r->rtm_type != RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000106 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000107 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100108 } else if (G_filter.tb == RT_TABLE_MAIN) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000109 if (r->rtm_type == RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000110 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000111 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000112 } else {
113 return 0;
114 }
115 }
116 }
117 } else {
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000118 if (G_filter.tb > 0 && G_filter.tb != tid) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000119 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000120 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000121 }
André Draszik2f24d302017-06-13 19:59:59 +0200122 if ((G_filter.scope ^ r->rtm_scope) & G_filter.scopemask)
123 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100124 if (G_filter.rdst.family
125 && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
126 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000127 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000128 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100129 if (G_filter.mdst.family
130 && (r->rtm_family != G_filter.mdst.family
131 || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
132 )
133 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000134 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000135 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100136 if (G_filter.rsrc.family
137 && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
138 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000139 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000140 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100141 if (G_filter.msrc.family
142 && (r->rtm_family != G_filter.msrc.family
143 || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
144 )
145 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000146 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000147 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000148
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100149 memset(&src, 0, sizeof(src));
150 memset(&dst, 0, sizeof(dst));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000151
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100152 if (tb[RTA_SRC]) {
153 src.bitlen = r->rtm_src_len;
154 src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
155 memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
156 }
157 if (tb[RTA_DST]) {
158 dst.bitlen = r->rtm_dst_len;
159 dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
160 memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
161 }
162
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100163 if (G_filter.rdst.family
164 && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
165 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000166 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100167 }
168 if (G_filter.mdst.family
169 && G_filter.mdst.bitlen >= 0
170 && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
171 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000172 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100173 }
174 if (G_filter.rsrc.family
175 && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
176 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000177 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100178 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100179 if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
180 && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
181 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000182 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100183 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100184 if (G_filter.oif != 0) {
185 if (!tb[RTA_OIF])
186 return 0;
187 if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
188 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100189 }
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000190
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100191 if (G_filter.flushb) {
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100192 struct nlmsghdr *fn;
193
Denys Vlasenkof1334712011-02-09 04:39:09 +0100194 /* We are creating route flush commands */
195
196 if (r->rtm_family == AF_INET6
197 && r->rtm_dst_len == 0
198 && r->rtm_type == RTN_UNREACHABLE
199 && tb[RTA_PRIORITY]
200 && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
201 ) {
202 return 0;
203 }
204
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100205 if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000206 if (flush_update())
Curt Brune69934702015-10-14 12:53:47 +0200207 xfunc_die();
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000208 }
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100209 fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000210 memcpy(fn, n, n->nlmsg_len);
211 fn->nlmsg_type = RTM_DELROUTE;
212 fn->nlmsg_flags = NLM_F_REQUEST;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100213 fn->nlmsg_seq = ++G_filter.rth->seq;
214 G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
215 G_filter.flushed = 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000216 return 0;
217 }
218
Denys Vlasenkof1334712011-02-09 04:39:09 +0100219 /* We are printing routes */
220
Glenn L McGrath16528552002-11-28 11:17:19 +0000221 if (n->nlmsg_type == RTM_DELROUTE) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000222 printf("Deleted ");
Glenn L McGrath16528552002-11-28 11:17:19 +0000223 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100224 if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
Denys Vlasenko3d8d5e82015-10-08 13:02:28 +0200225 printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
Glenn L McGrath16528552002-11-28 11:17:19 +0000226 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000227
228 if (tb[RTA_DST]) {
229 if (r->rtm_dst_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200230 printf("%s/%u ",
231 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
232 r->rtm_dst_len
233 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000234 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000235 printf("%s ", format_host(r->rtm_family,
236 RTA_PAYLOAD(tb[RTA_DST]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200237 RTA_DATA(tb[RTA_DST]))
238 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000239 }
240 } else if (r->rtm_dst_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000241 printf("0/%d ", r->rtm_dst_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000242 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000243 printf("default ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000244 }
245 if (tb[RTA_SRC]) {
246 if (r->rtm_src_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200247 printf("from %s/%u ",
248 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
249 r->rtm_src_len
250 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000251 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000252 printf("from %s ", format_host(r->rtm_family,
253 RTA_PAYLOAD(tb[RTA_SRC]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200254 RTA_DATA(tb[RTA_SRC]))
255 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000256 }
257 } else if (r->rtm_src_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000258 printf("from 0/%u ", r->rtm_src_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000259 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100260 if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000261 printf("via %s ", format_host(r->rtm_family,
262 RTA_PAYLOAD(tb[RTA_GATEWAY]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200263 RTA_DATA(tb[RTA_GATEWAY]))
264 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000265 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100266 if (tb[RTA_OIF]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000267 printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
Glenn L McGrath16528552002-11-28 11:17:19 +0000268 }
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000269#if ENABLE_FEATURE_IP_RULE
270 if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
271 printf("table %s ", rtnl_rttable_n2a(tid));
272#endif
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000273
André Draszik2f24d302017-06-13 19:59:59 +0200274 /* Todo: parse & show "proto kernel" here */
275 if (!(r->rtm_flags & RTM_F_CLONED)) {
276 if ((r->rtm_scope != RT_SCOPE_UNIVERSE) && G_filter.scopemask != -1)
277 printf("scope %s ", rtnl_rtscope_n2a(r->rtm_scope));
278 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100279
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100280 if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000281 /* Do not use format_host(). It is our local addr
282 and symbolic name will not be useful.
283 */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000284 printf(" src %s ", rt_addr_n2a(r->rtm_family,
Denys Vlasenko926d8012015-10-14 13:56:42 +0200285 RTA_DATA(tb[RTA_PREFSRC])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000286 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000287 if (tb[RTA_PRIORITY]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000288 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
Glenn L McGrath16528552002-11-28 11:17:19 +0000289 }
Michael Tokarev1a114392014-07-28 10:05:41 +0400290 if (r->rtm_flags & RTNH_F_DEAD) {
291 printf("dead ");
292 }
293 if (r->rtm_flags & RTNH_F_ONLINK) {
294 printf("onlink ");
295 }
296 if (r->rtm_flags & RTNH_F_PERVASIVE) {
297 printf("pervasive ");
298 }
299 if (r->rtm_flags & RTM_F_NOTIFY) {
300 printf("notify ");
301 }
302
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000303 if (r->rtm_family == AF_INET6) {
304 struct rta_cacheinfo *ci = NULL;
Glenn L McGrath16528552002-11-28 11:17:19 +0000305 if (tb[RTA_CACHEINFO]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000306 ci = RTA_DATA(tb[RTA_CACHEINFO]);
Glenn L McGrath16528552002-11-28 11:17:19 +0000307 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000308 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000309 if (r->rtm_flags & RTM_F_CLONED) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000310 printf("%c cache ", _SL_);
Glenn L McGrath16528552002-11-28 11:17:19 +0000311 }
312 if (ci->rta_expires) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000313 printf(" expires %dsec", ci->rta_expires / get_hz());
Glenn L McGrath16528552002-11-28 11:17:19 +0000314 }
315 if (ci->rta_error != 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000316 printf(" error %d", ci->rta_error);
Glenn L McGrath16528552002-11-28 11:17:19 +0000317 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000318 } else if (ci) {
319 if (ci->rta_error != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000320 printf(" error %d", ci->rta_error);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000321 }
322 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100323 if (tb[RTA_IIF] && G_filter.iif == 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000324 printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000325 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000326 bb_putchar('\n');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000327 return 0;
328}
329
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200330static int str_is_lock(const char *str)
331{
332 return strcmp(str, "lock") == 0;
333}
334
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000335/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000336static int iproute_modify(int cmd, unsigned flags, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000337{
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200338 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000339 static const char keywords[] ALIGN1 =
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200340 "src\0""via\0"
341 "mtu\0""advmss\0"
342 "scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
Michael Tokarev1a114392014-07-28 10:05:41 +0400343 "dev\0""oif\0""to\0""metric\0""onlink\0";
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200344#define keyword_via (keywords + sizeof("src"))
345#define keyword_mtu (keyword_via + sizeof("via"))
346#define keyword_advmss (keyword_mtu + sizeof("mtu"))
347#define keyword_scope (keyword_advmss + sizeof("advmss"))
348#define keyword_proto (keyword_scope + sizeof("scope"))
349#define keyword_table (keyword_proto + sizeof("protocol"))
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000350 enum {
351 ARG_src,
352 ARG_via,
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200353 ARG_mtu,
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200354 ARG_advmss,
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100355 ARG_scope,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000356 ARG_protocol,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000357IF_FEATURE_IP_RULE(ARG_table,)
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000358 ARG_dev,
359 ARG_oif,
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000360 ARG_to,
361 ARG_metric,
Michael Tokarev1a114392014-07-28 10:05:41 +0400362 ARG_onlink,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000363 };
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000364 enum {
365 gw_ok = 1 << 0,
366 dst_ok = 1 << 1,
367 proto_ok = 1 << 2,
368 type_ok = 1 << 3
369 };
370 struct rtnl_handle rth;
371 struct {
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200372 struct nlmsghdr n;
373 struct rtmsg r;
374 char buf[1024];
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000375 } req;
376 char mxbuf[256];
377 struct rtattr * mxrta = (void*)mxbuf;
378 unsigned mxlock = 0;
379 char *d = NULL;
380 smalluint ok = 0;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100381 smalluint scope_ok = 0;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000382 int arg;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000383
384 memset(&req, 0, sizeof(req));
385
386 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000387 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000388 req.n.nlmsg_type = cmd;
389 req.r.rtm_family = preferred_family;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100390 if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000391 req.r.rtm_table = RT_TABLE_MAIN;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100392 if (RT_SCOPE_NOWHERE != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000393 req.r.rtm_scope = RT_SCOPE_NOWHERE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000394
395 if (cmd != RTM_DELROUTE) {
Denys Vlasenko34ecc3b2016-08-14 01:30:34 +0200396 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100397 if (RTPROT_BOOT != 0)
398 req.r.rtm_protocol = RTPROT_BOOT;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100399 if (RTN_UNICAST != 0)
400 req.r.rtm_type = RTN_UNICAST;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000401 }
402
403 mxrta->rta_type = RTA_METRICS;
404 mxrta->rta_len = RTA_LENGTH(0);
405
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000406 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000407 arg = index_in_substrings(keywords, *argv);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000408 if (arg == ARG_src) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000409 inet_prefix addr;
410 NEXT_ARG();
411 get_addr(&addr, *argv, req.r.rtm_family);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000412 if (req.r.rtm_family == AF_UNSPEC)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000413 req.r.rtm_family = addr.family;
414 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000415 } else if (arg == ARG_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000416 inet_prefix addr;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000417 ok |= gw_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000418 NEXT_ARG();
419 get_addr(&addr, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000420 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000421 req.r.rtm_family = addr.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000422 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000423 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000424 } else if (arg == ARG_mtu) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000425 unsigned mtu;
426 NEXT_ARG();
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200427 if (str_is_lock(*argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000428 mxlock |= (1 << RTAX_MTU);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000429 NEXT_ARG();
430 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200431 mtu = get_unsigned(*argv, keyword_mtu);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000432 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200433 } else if (arg == ARG_advmss) {
434 unsigned mss;
435 NEXT_ARG();
436 if (str_is_lock(*argv)) {
437 mxlock |= (1 << RTAX_ADVMSS);
438 NEXT_ARG();
439 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200440 mss = get_unsigned(*argv, keyword_advmss);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200441 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100442 } else if (arg == ARG_scope) {
443 uint32_t scope;
444 NEXT_ARG();
445 if (rtnl_rtscope_a2n(&scope, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200446 invarg_1_to_2(*argv, keyword_scope);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100447 req.r.rtm_scope = scope;
448 scope_ok = 1;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000449 } else if (arg == ARG_protocol) {
Eric Andersend78aea82006-01-30 18:00:02 +0000450 uint32_t prot;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000451 NEXT_ARG();
452 if (rtnl_rtprot_a2n(&prot, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200453 invarg_1_to_2(*argv, keyword_proto);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000454 req.r.rtm_protocol = prot;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000455 ok |= proto_ok;
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000456#if ENABLE_FEATURE_IP_RULE
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000457 } else if (arg == ARG_table) {
Denis Vlasenkocda6c632006-12-15 00:59:35 +0000458 uint32_t tid;
459 NEXT_ARG();
460 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200461 invarg_1_to_2(*argv, keyword_table);
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000462 if (tid < 256)
463 req.r.rtm_table = tid;
464 else {
465 req.r.rtm_table = RT_TABLE_UNSPEC;
466 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
467 }
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000468#endif
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000469 } else if (arg == ARG_dev || arg == ARG_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000470 NEXT_ARG();
471 d = *argv;
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000472 } else if (arg == ARG_metric) {
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200473//TODO: "metric", "priority" and "preference" are synonyms
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000474 uint32_t metric;
475 NEXT_ARG();
Denis Vlasenko76140a72009-03-05 09:21:57 +0000476 metric = get_u32(*argv, "metric");
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000477 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
Michael Tokarev1a114392014-07-28 10:05:41 +0400478 } else if (arg == ARG_onlink) {
479 req.r.rtm_flags |= RTNH_F_ONLINK;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000480 } else {
481 int type;
482 inet_prefix dst;
483
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000484 if (arg == ARG_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000485 NEXT_ARG();
486 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000487 if ((**argv < '0' || **argv > '9')
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100488 && rtnl_rtntype_a2n(&type, *argv) == 0
489 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000490 NEXT_ARG();
491 req.r.rtm_type = type;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000492 ok |= type_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000493 }
494
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000495 if (ok & dst_ok) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000496 duparg2("to", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000497 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000498 get_prefix(&dst, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000499 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000500 req.r.rtm_family = dst.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000501 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000502 req.r.rtm_dst_len = dst.bitlen;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000503 ok |= dst_ok;
Glenn L McGrath16528552002-11-28 11:17:19 +0000504 if (dst.bytelen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000505 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
Glenn L McGrath16528552002-11-28 11:17:19 +0000506 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000507 }
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200508/* Other keywords recognized by iproute2-3.19.0: */
509#if 0
510 } else if (strcmp(*argv, "from") == 0) {
511 inet_prefix addr;
512 NEXT_ARG();
513 get_prefix(&addr, *argv, req.r.rtm_family);
514 if (req.r.rtm_family == AF_UNSPEC)
515 req.r.rtm_family = addr.family;
516 if (addr.bytelen)
517 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
518 req.r.rtm_src_len = addr.bitlen;
519 } else if (strcmp(*argv, "tos") == 0 ||
520 matches(*argv, "dsfield") == 0) {
521 __u32 tos;
522 NEXT_ARG();
523 if (rtnl_dsfield_a2n(&tos, *argv))
524 invarg("\"tos\" value is invalid\n", *argv);
525 req.r.rtm_tos = tos;
526 } else if (strcmp(*argv, "hoplimit") == 0) {
527 unsigned hoplimit;
528 NEXT_ARG();
529 if (strcmp(*argv, "lock") == 0) {
530 mxlock |= (1<<RTAX_HOPLIMIT);
531 NEXT_ARG();
532 }
533 if (get_unsigned(&hoplimit, *argv, 0))
534 invarg("\"hoplimit\" value is invalid\n", *argv);
535 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200536 } else if (matches(*argv, "reordering") == 0) {
537 unsigned reord;
538 NEXT_ARG();
539 if (strcmp(*argv, "lock") == 0) {
540 mxlock |= (1<<RTAX_REORDERING);
541 NEXT_ARG();
542 }
543 if (get_unsigned(&reord, *argv, 0))
544 invarg("\"reordering\" value is invalid\n", *argv);
545 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
546 } else if (strcmp(*argv, "rtt") == 0) {
547 unsigned rtt;
548 NEXT_ARG();
549 if (strcmp(*argv, "lock") == 0) {
550 mxlock |= (1<<RTAX_RTT);
551 NEXT_ARG();
552 }
553 if (get_time_rtt(&rtt, *argv, &raw))
554 invarg("\"rtt\" value is invalid\n", *argv);
555 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
556 (raw) ? rtt : rtt * 8);
557 } else if (strcmp(*argv, "rto_min") == 0) {
558 unsigned rto_min;
559 NEXT_ARG();
560 mxlock |= (1<<RTAX_RTO_MIN);
561 if (get_time_rtt(&rto_min, *argv, &raw))
562 invarg("\"rto_min\" value is invalid\n",
563 *argv);
564 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
565 rto_min);
566 } else if (matches(*argv, "window") == 0) {
567 unsigned win;
568 NEXT_ARG();
569 if (strcmp(*argv, "lock") == 0) {
570 mxlock |= (1<<RTAX_WINDOW);
571 NEXT_ARG();
572 }
573 if (get_unsigned(&win, *argv, 0))
574 invarg("\"window\" value is invalid\n", *argv);
575 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
576 } else if (matches(*argv, "cwnd") == 0) {
577 unsigned win;
578 NEXT_ARG();
579 if (strcmp(*argv, "lock") == 0) {
580 mxlock |= (1<<RTAX_CWND);
581 NEXT_ARG();
582 }
583 if (get_unsigned(&win, *argv, 0))
584 invarg("\"cwnd\" value is invalid\n", *argv);
585 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
586 } else if (matches(*argv, "initcwnd") == 0) {
587 unsigned win;
588 NEXT_ARG();
589 if (strcmp(*argv, "lock") == 0) {
590 mxlock |= (1<<RTAX_INITCWND);
591 NEXT_ARG();
592 }
593 if (get_unsigned(&win, *argv, 0))
594 invarg("\"initcwnd\" value is invalid\n", *argv);
595 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
596 } else if (matches(*argv, "initrwnd") == 0) {
597 unsigned win;
598 NEXT_ARG();
599 if (strcmp(*argv, "lock") == 0) {
600 mxlock |= (1<<RTAX_INITRWND);
601 NEXT_ARG();
602 }
603 if (get_unsigned(&win, *argv, 0))
604 invarg("\"initrwnd\" value is invalid\n", *argv);
605 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
606 } else if (matches(*argv, "features") == 0) {
607 unsigned int features = 0;
608
609 while (argc > 0) {
610 NEXT_ARG();
611
612 if (strcmp(*argv, "ecn") == 0)
613 features |= RTAX_FEATURE_ECN;
614 else
615 invarg("\"features\" value not valid\n", *argv);
616 break;
617 }
618
619 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features);
620 } else if (matches(*argv, "quickack") == 0) {
621 unsigned quickack;
622 NEXT_ARG();
623 if (get_unsigned(&quickack, *argv, 0))
624 invarg("\"quickack\" value is invalid\n", *argv);
625 if (quickack != 1 && quickack != 0)
626 invarg("\"quickack\" value should be 0 or 1\n", *argv);
627 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
628 } else if (matches(*argv, "rttvar") == 0) {
629 unsigned win;
630 NEXT_ARG();
631 if (strcmp(*argv, "lock") == 0) {
632 mxlock |= (1<<RTAX_RTTVAR);
633 NEXT_ARG();
634 }
635 if (get_time_rtt(&win, *argv, &raw))
636 invarg("\"rttvar\" value is invalid\n", *argv);
637 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
638 (raw) ? win : win * 4);
639 } else if (matches(*argv, "ssthresh") == 0) {
640 unsigned win;
641 NEXT_ARG();
642 if (strcmp(*argv, "lock") == 0) {
643 mxlock |= (1<<RTAX_SSTHRESH);
644 NEXT_ARG();
645 }
646 if (get_unsigned(&win, *argv, 0))
647 invarg("\"ssthresh\" value is invalid\n", *argv);
648 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
649 } else if (matches(*argv, "realms") == 0) {
650 __u32 realm;
651 NEXT_ARG();
652 if (get_rt_realms(&realm, *argv))
653 invarg("\"realm\" value is invalid\n", *argv);
654 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
655 } else if (strcmp(*argv, "nexthop") == 0) {
656 nhs_ok = 1;
657 break;
658 }
659#endif
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000660 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000661 }
662
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000663 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000664
Eric Andersen5780adb2002-11-15 09:12:47 +0000665 if (d) {
666 int idx;
667
668 ll_init_map(&rth);
669
670 if (d) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000671 idx = xll_name_to_index(d);
Eric Andersen5780adb2002-11-15 09:12:47 +0000672 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
673 }
674 }
675
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000676 if (mxrta->rta_len > RTA_LENGTH(0)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000677 if (mxlock) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000678 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
Glenn L McGrath16528552002-11-28 11:17:19 +0000679 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000680 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
681 }
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000682
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100683 if (!scope_ok) {
684 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
685 req.r.rtm_scope = RT_SCOPE_HOST;
686 else
687 if (req.r.rtm_type == RTN_BROADCAST
688 || req.r.rtm_type == RTN_MULTICAST
689 || req.r.rtm_type == RTN_ANYCAST
690 ) {
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000691 req.r.rtm_scope = RT_SCOPE_LINK;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100692 }
693 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
694 if (cmd == RTM_DELROUTE)
695 req.r.rtm_scope = RT_SCOPE_NOWHERE;
696 else if (!(ok & gw_ok))
697 req.r.rtm_scope = RT_SCOPE_LINK;
698 }
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000699 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000700
Glenn L McGrath16528552002-11-28 11:17:19 +0000701 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000702 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000703 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000704
Glenn L McGrath16528552002-11-28 11:17:19 +0000705 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000706 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +0000707 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000708
709 return 0;
710}
711
712static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
713{
714 struct {
715 struct nlmsghdr nlh;
716 struct rtmsg rtm;
717 } req;
718 struct sockaddr_nl nladdr;
719
720 memset(&nladdr, 0, sizeof(nladdr));
721 memset(&req, 0, sizeof(req));
722 nladdr.nl_family = AF_NETLINK;
723
724 req.nlh.nlmsg_len = sizeof(req);
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000725 if (RTM_GETROUTE)
726 req.nlh.nlmsg_type = RTM_GETROUTE;
727 if (NLM_F_ROOT | NLM_F_REQUEST)
728 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
729 /*req.nlh.nlmsg_pid = 0; - memset did it already */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000730 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
731 req.rtm.rtm_family = family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000732 if (RTM_F_CLONED)
733 req.rtm.rtm_flags = RTM_F_CLONED;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000734
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000735 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000736}
737
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000738static void iproute_flush_cache(void)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000739{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000740 static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000741 int flush_fd = open_or_warn(fn, O_WRONLY);
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000742
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000743 if (flush_fd < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000744 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000745 }
746
Denis Vlasenko89ef65f2007-01-29 23:43:18 +0000747 if (write(flush_fd, "-1", 2) < 2) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100748 bb_perror_msg("can't flush routing cache");
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000749 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000750 }
751 close(flush_fd);
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000752}
753
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000754static void iproute_reset_filter(void)
755{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100756 memset(&G_filter, 0, sizeof(G_filter));
757 G_filter.mdst.bitlen = -1;
758 G_filter.msrc.bitlen = -1;
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000759}
760
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000761/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000762static int iproute_list_or_flush(char **argv, int flush)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000763{
764 int do_ipv6 = preferred_family;
765 struct rtnl_handle rth;
766 char *id = NULL;
767 char *od = NULL;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000768 static const char keywords[] ALIGN1 =
André Draszik2f24d302017-06-13 19:59:59 +0200769 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000770 /* "ip route list/flush" parameters: */
771 "protocol\0" "dev\0" "oif\0" "iif\0"
772 "via\0" "table\0" "cache\0"
André Draszik2f24d302017-06-13 19:59:59 +0200773 "from\0" "to\0" "scope\0"
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000774 /* and possible further keywords */
775 "all\0"
776 "root\0"
777 "match\0"
778 "exact\0"
779 "main\0"
780 ;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000781 enum {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000782 KW_proto, KW_dev, KW_oif, KW_iif,
783 KW_via, KW_table, KW_cache,
André Draszik2f24d302017-06-13 19:59:59 +0200784 KW_from, KW_to, KW_scope,
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000785 /* */
786 KW_all,
787 KW_root,
788 KW_match,
789 KW_exact,
790 KW_main,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000791 };
792 int arg, parm;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000793
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000794 iproute_reset_filter();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100795 G_filter.tb = RT_TABLE_MAIN;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000796
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000797 if (flush && !*argv)
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000798 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000799
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000800 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000801 arg = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000802 if (arg == KW_proto) {
Eric Andersend78aea82006-01-30 18:00:02 +0000803 uint32_t prot = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000804 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100805 //G_filter.protocolmask = -1;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000806 if (rtnl_rtprot_a2n(&prot, *argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000807 if (index_in_strings(keywords, *argv) != KW_all)
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200808 invarg_1_to_2(*argv, "protocol");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000809 prot = 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100810 //G_filter.protocolmask = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000811 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100812 //G_filter.protocol = prot;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000813 } else if (arg == KW_dev || arg == KW_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000814 NEXT_ARG();
815 od = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000816 } else if (arg == KW_iif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000817 NEXT_ARG();
818 id = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000819 } else if (arg == KW_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000820 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100821 get_prefix(&G_filter.rvia, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000822 } else if (arg == KW_table) { /* table all/cache/main */
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000823 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000824 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000825 if (parm == KW_cache)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100826 G_filter.tb = -1;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000827 else if (parm == KW_all)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100828 G_filter.tb = 0;
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000829 else if (parm != KW_main) {
830#if ENABLE_FEATURE_IP_RULE
831 uint32_t tid;
832 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200833 invarg_1_to_2(*argv, "table");
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100834 G_filter.tb = tid;
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000835#else
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200836 invarg_1_to_2(*argv, "table");
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000837#endif
838 }
Denis Vlasenko79c69042007-11-27 09:42:33 +0000839 } else if (arg == KW_cache) {
840 /* The command 'ip route flush cache' is used by OpenSWAN.
841 * Assuming it's a synonym for 'ip route flush table cache' */
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100842 G_filter.tb = -1;
André Draszik2f24d302017-06-13 19:59:59 +0200843 } else if (arg == KW_scope) {
844 uint32_t scope;
845 NEXT_ARG();
846 G_filter.scopemask = -1;
847 if (rtnl_rtscope_a2n(&scope, *argv)) {
848 if (strcmp(*argv, "all") != 0)
849 invarg_1_to_2(*argv, "scope");
850 scope = RT_SCOPE_NOWHERE;
851 G_filter.scopemask = 0;
852 }
853 G_filter.scope = scope;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000854 } else if (arg == KW_from) {
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000855 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000856 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000857 if (parm == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000858 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100859 get_prefix(&G_filter.rsrc, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000860 } else if (parm == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000861 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100862 get_prefix(&G_filter.msrc, *argv, do_ipv6);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000863 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000864 if (parm == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000865 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100866 get_prefix(&G_filter.msrc, *argv, do_ipv6);
867 G_filter.rsrc = G_filter.msrc;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000868 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000869 } else { /* "to" is the default parameter */
870 if (arg == KW_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000871 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000872 arg = index_in_substrings(keywords, *argv);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000873 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000874 /* parm = arg; - would be more plausible, but we reuse 'arg' here */
875 if (arg == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000876 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100877 get_prefix(&G_filter.rdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000878 } else if (arg == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000879 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100880 get_prefix(&G_filter.mdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000881 } else { /* "to exact" is the default */
882 if (arg == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000883 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100884 get_prefix(&G_filter.mdst, *argv, do_ipv6);
885 G_filter.rdst = G_filter.mdst;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000886 }
887 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000888 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000889 }
890
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100891 if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000892 do_ipv6 = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000893 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000894
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000895 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000896 ll_init_map(&rth);
897
898 if (id || od) {
899 int idx;
900
901 if (id) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000902 idx = xll_name_to_index(id);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100903 G_filter.iif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000904 }
905 if (od) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000906 idx = xll_name_to_index(od);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100907 G_filter.oif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000908 }
909 }
910
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000911 if (flush) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000912 char flushb[4096-512];
913
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100914 if (G_filter.tb == -1) { /* "flush table cache" */
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000915 if (do_ipv6 != AF_INET6)
916 iproute_flush_cache();
917 if (do_ipv6 == AF_INET)
918 return 0;
919 }
920
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100921 G_filter.flushb = flushb;
922 G_filter.flushp = 0;
923 G_filter.flushe = sizeof(flushb);
924 G_filter.rth = &rth;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000925
926 for (;;) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000927 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100928 G_filter.flushed = 0;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000929 xrtnl_dump_filter(&rth, print_route, NULL);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100930 if (G_filter.flushed == 0)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000931 return 0;
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000932 if (flush_update())
933 return 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000934 }
935 }
936
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100937 if (G_filter.tb != -1) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000938 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000939 } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100940 bb_perror_msg_and_die("can't send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000941 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000942 xrtnl_dump_filter(&rth, print_route, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000943
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000944 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000945}
946
947
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000948/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000949static int iproute_get(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000950{
951 struct rtnl_handle rth;
952 struct {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000953 struct nlmsghdr n;
954 struct rtmsg r;
955 char buf[1024];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000956 } req;
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000957 char *idev = NULL;
958 char *odev = NULL;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000959 bool connected = 0;
960 bool from_ok = 0;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000961 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000962 "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000963
964 memset(&req, 0, sizeof(req));
965
966 iproute_reset_filter();
967
968 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000969 if (NLM_F_REQUEST)
970 req.n.nlmsg_flags = NLM_F_REQUEST;
971 if (RTM_GETROUTE)
972 req.n.nlmsg_type = RTM_GETROUTE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000973 req.r.rtm_family = preferred_family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000974 /*req.r.rtm_table = 0; - memset did this already */
975 /*req.r.rtm_protocol = 0;*/
976 /*req.r.rtm_scope = 0;*/
977 /*req.r.rtm_type = 0;*/
978 /*req.r.rtm_src_len = 0;*/
979 /*req.r.rtm_dst_len = 0;*/
980 /*req.r.rtm_tos = 0;*/
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000981
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000982 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000983 switch (index_in_strings(options, *argv)) {
Glenn L McGrath18eae002002-12-02 00:54:10 +0000984 case 0: /* from */
985 {
986 inet_prefix addr;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000987 NEXT_ARG();
Glenn L McGrath18eae002002-12-02 00:54:10 +0000988 from_ok = 1;
989 get_prefix(&addr, *argv, req.r.rtm_family);
990 if (req.r.rtm_family == AF_UNSPEC) {
991 req.r.rtm_family = addr.family;
992 }
993 if (addr.bytelen) {
994 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
995 }
996 req.r.rtm_src_len = addr.bitlen;
997 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000998 }
Glenn L McGrath18eae002002-12-02 00:54:10 +0000999 case 1: /* iif */
1000 NEXT_ARG();
1001 idev = *argv;
1002 break;
1003 case 2: /* oif */
1004 case 3: /* dev */
1005 NEXT_ARG();
1006 odev = *argv;
1007 break;
1008 case 4: /* notify */
1009 req.r.rtm_flags |= RTM_F_NOTIFY;
1010 break;
1011 case 5: /* connected */
1012 connected = 1;
1013 break;
1014 case 6: /* to */
1015 NEXT_ARG();
1016 default:
1017 {
1018 inet_prefix addr;
1019 get_prefix(&addr, *argv, req.r.rtm_family);
1020 if (req.r.rtm_family == AF_UNSPEC) {
1021 req.r.rtm_family = addr.family;
1022 }
1023 if (addr.bytelen) {
1024 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
1025 }
1026 req.r.rtm_dst_len = addr.bitlen;
1027 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001028 }
Christian Hornung3bbfb582010-11-03 14:08:00 +01001029 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001030 }
1031
1032 if (req.r.rtm_dst_len == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001033 bb_error_msg_and_die("need at least destination address");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001034 }
1035
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001036 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001037
1038 ll_init_map(&rth);
1039
1040 if (idev || odev) {
1041 int idx;
1042
1043 if (idev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001044 idx = xll_name_to_index(idev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001045 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1046 }
1047 if (odev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001048 idx = xll_name_to_index(odev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001049 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1050 }
1051 }
1052
Glenn L McGrath16528552002-11-28 11:17:19 +00001053 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001054 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +00001055 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001056
Glenn L McGrath16528552002-11-28 11:17:19 +00001057 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001058 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001059 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001060
1061 if (connected && !from_ok) {
1062 struct rtmsg *r = NLMSG_DATA(&req.n);
1063 int len = req.n.nlmsg_len;
1064 struct rtattr * tb[RTA_MAX+1];
1065
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001066 print_route(NULL, &req.n, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001067
1068 if (req.n.nlmsg_type != RTM_NEWROUTE) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001069 bb_error_msg_and_die("not a route?");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001070 }
1071 len -= NLMSG_LENGTH(sizeof(*r));
1072 if (len < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001073 bb_error_msg_and_die("wrong len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001074 }
1075
1076 memset(tb, 0, sizeof(tb));
1077 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1078
1079 if (tb[RTA_PREFSRC]) {
1080 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1081 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1082 } else if (!tb[RTA_SRC]) {
Denys Vlasenko651a2692010-03-23 16:25:17 +01001083 bb_error_msg_and_die("can't connect the route");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001084 }
Glenn L McGrath16528552002-11-28 11:17:19 +00001085 if (!odev && tb[RTA_OIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001086 tb[RTA_OIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001087 }
1088 if (tb[RTA_GATEWAY]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001089 tb[RTA_GATEWAY]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001090 }
1091 if (!idev && tb[RTA_IIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001092 tb[RTA_IIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001093 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001094 req.n.nlmsg_flags = NLM_F_REQUEST;
1095 req.n.nlmsg_type = RTM_GETROUTE;
1096
Glenn L McGrath16528552002-11-28 11:17:19 +00001097 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001098 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001099 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001100 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001101 print_route(NULL, &req.n, NULL);
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001102 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001103}
1104
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001105/* Return value becomes exitcode. It's okay to not return at all */
Denys Vlasenko2e9b5512010-07-24 23:27:38 +02001106int FAST_FUNC do_iproute(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001107{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001108 static const char ip_route_commands[] ALIGN1 =
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001109 "a\0""add\0""append\0""change\0""chg\0"
1110 "delete\0""get\0""list\0""show\0"
1111 "prepend\0""replace\0""test\0""flush\0"
1112 ;
1113 enum {
1114 CMD_a = 0, CMD_add, CMD_append, CMD_change, CMD_chg,
1115 CMD_delete, CMD_get, CMD_list, CMD_show,
1116 CMD_prepend, CMD_replace, CMD_test, CMD_flush,
1117 };
Denis Vlasenko83c44222008-01-04 15:28:28 +00001118 int command_num;
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001119 unsigned flags = 0;
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001120 int cmd = RTM_NEWROUTE;
1121
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +02001122 INIT_G();
1123
Denis Vlasenko83c44222008-01-04 15:28:28 +00001124 if (!*argv)
1125 return iproute_list_or_flush(argv, 0);
1126
Denis Vlasenko5af906e2006-11-05 18:05:09 +00001127 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
1128 /* It probably means that it is using "first match" rule */
Denis Vlasenko83c44222008-01-04 15:28:28 +00001129 command_num = index_in_substrings(ip_route_commands, *argv);
1130
Denis Vlasenkoc16bd212006-09-27 19:51:06 +00001131 switch (command_num) {
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001132 case CMD_a:
1133 case CMD_add:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001134 flags = NLM_F_CREATE|NLM_F_EXCL;
1135 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001136 case CMD_append:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001137 flags = NLM_F_CREATE|NLM_F_APPEND;
1138 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001139 case CMD_change:
1140 case CMD_chg:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001141 flags = NLM_F_REPLACE;
1142 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001143 case CMD_delete:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001144 cmd = RTM_DELROUTE;
1145 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001146 case CMD_get:
1147 return iproute_get(argv + 1);
1148 case CMD_list:
1149 case CMD_show:
1150 return iproute_list_or_flush(argv + 1, 0);
1151 case CMD_prepend:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001152 flags = NLM_F_CREATE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001153 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001154 case CMD_replace:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001155 flags = NLM_F_CREATE|NLM_F_REPLACE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001156 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001157 case CMD_test:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001158 flags = NLM_F_EXCL;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001159 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001160 case CMD_flush:
1161 return iproute_list_or_flush(argv + 1, 1);
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001162 default:
Denys Vlasenko0f296a32015-10-14 13:21:01 +02001163 invarg_1_to_2(*argv, applet_name);
Glenn L McGrath16528552002-11-28 11:17:19 +00001164 }
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001165
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001166 return iproute_modify(cmd, flags, argv + 1);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001167}