blob: 2a8610ea66376f3d864c6b0f40121d6918ea42d3 [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
Eugene Rudoyecce3a12017-10-19 00:05:11 +020017#include <linux/version.h>
18/* RTA_TABLE is not a define, can't test with ifdef. */
19/* As a proxy, test which kernels toolchain expects: */
20#define HAVE_RTA_TABLE (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
21
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000022#ifndef RTAX_RTTVAR
23#define RTAX_RTTVAR RTAX_HOPS
24#endif
25
26
Denys Vlasenko36659fd2010-02-05 14:40:23 +010027struct filter_t {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000028 int tb;
Denis Vlasenko3e57adb2008-05-31 07:33:18 +000029 smallint flushed;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000030 char *flushb;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000031 int flushp;
32 int flushe;
33 struct rtnl_handle *rth;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010034 //int protocol, protocolmask; - write-only fields?!
André Draszik2f24d302017-06-13 19:59:59 +020035 int scope, scopemask;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010036 //int type; - read-only
37 //int typemask; - unused
38 //int tos, tosmask; - unused
Denys Vlasenkof1334712011-02-09 04:39:09 +010039 int iif;
40 int oif;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010041 //int realm, realmmask; - unused
42 //inet_prefix rprefsrc; - read-only
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000043 inet_prefix rvia;
44 inet_prefix rdst;
45 inet_prefix mdst;
46 inet_prefix rsrc;
47 inet_prefix msrc;
Denys Vlasenko36659fd2010-02-05 14:40:23 +010048} FIX_ALIASING;
49typedef struct filter_t filter_t;
Denis Vlasenko540a2a12007-04-07 01:14:45 +000050
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020051#define G_filter (*(filter_t*)bb_common_bufsiz1)
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +020052#define INIT_G() do { setup_common_bufsiz(); } while (0)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000053
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000054static int flush_update(void)
55{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010056 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
Denys Vlasenko651a2692010-03-23 16:25:17 +010057 bb_perror_msg("can't send flush request");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000058 return -1;
59 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010060 G_filter.flushp = 0;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000061 return 0;
62}
63
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020064static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000065 struct nlmsghdr *n, void *arg UNUSED_PARAM)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000066{
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000067 struct rtmsg *r = NLMSG_DATA(n);
68 int len = n->nlmsg_len;
Denys Vlasenko3bb235c2011-02-23 01:20:44 +010069 struct rtattr *tb[RTA_MAX+1];
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +000070 inet_prefix dst;
71 inet_prefix src;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000072 int host_len = -1;
Lukasz Nowakb42107f2016-12-13 12:58:31 +000073 uint32_t tid;
Eric Andersenc7bda1c2004-03-15 08:29:22 +000074
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000075 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
76 fprintf(stderr, "Not a route: %08x %08x %08x\n",
77 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
78 return 0;
79 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010080 if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +000081 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000082 len -= NLMSG_LENGTH(sizeof(*r));
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +000083 if (len < 0)
84 bb_error_msg_and_die("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000085
Denys Vlasenko68ae5422018-02-08 08:42:37 +010086 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
Lukasz Nowakb42107f2016-12-13 12:58:31 +000087 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
88
Eugene Rudoyecce3a12017-10-19 00:05:11 +020089#if HAVE_RTA_TABLE
Lukasz Nowakb42107f2016-12-13 12:58:31 +000090 if (tb[RTA_TABLE])
91 tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
92 else
Eugene Rudoyecce3a12017-10-19 00:05:11 +020093#endif
Lukasz Nowakb42107f2016-12-13 12:58:31 +000094 tid = r->rtm_table;
95
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000096 if (r->rtm_family == AF_INET6)
97 host_len = 128;
98 else if (r->rtm_family == AF_INET)
99 host_len = 32;
100
101 if (r->rtm_family == AF_INET6) {
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100102 if (G_filter.tb) {
103 if (G_filter.tb < 0) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000104 if (!(r->rtm_flags & RTM_F_CLONED)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000105 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000106 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000107 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000108 if (r->rtm_flags & RTM_F_CLONED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000109 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000110 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100111 if (G_filter.tb == RT_TABLE_LOCAL) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000112 if (r->rtm_type != RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000113 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000114 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100115 } else if (G_filter.tb == RT_TABLE_MAIN) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000116 if (r->rtm_type == RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000117 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000118 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000119 } else {
120 return 0;
121 }
122 }
123 }
124 } else {
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000125 if (G_filter.tb > 0 && G_filter.tb != tid) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000126 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000127 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000128 }
André Draszik2f24d302017-06-13 19:59:59 +0200129 if ((G_filter.scope ^ r->rtm_scope) & G_filter.scopemask)
130 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100131 if (G_filter.rdst.family
132 && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
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.mdst.family
137 && (r->rtm_family != G_filter.mdst.family
138 || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
139 )
140 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000141 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000142 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100143 if (G_filter.rsrc.family
144 && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
145 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000146 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000147 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100148 if (G_filter.msrc.family
149 && (r->rtm_family != G_filter.msrc.family
150 || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
151 )
152 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000153 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000154 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000155
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100156 memset(&src, 0, sizeof(src));
157 memset(&dst, 0, sizeof(dst));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000158
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100159 if (tb[RTA_SRC]) {
160 src.bitlen = r->rtm_src_len;
161 src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
162 memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
163 }
164 if (tb[RTA_DST]) {
165 dst.bitlen = r->rtm_dst_len;
166 dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
167 memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
168 }
169
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100170 if (G_filter.rdst.family
171 && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
172 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000173 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100174 }
175 if (G_filter.mdst.family
176 && G_filter.mdst.bitlen >= 0
177 && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
178 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000179 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100180 }
181 if (G_filter.rsrc.family
182 && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
183 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000184 return 0;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100185 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100186 if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
187 && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
188 ) {
Glenn L McGrathfbf0b8a2003-04-26 02:22:19 +0000189 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100190 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100191 if (G_filter.oif != 0) {
192 if (!tb[RTA_OIF])
193 return 0;
194 if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
195 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100196 }
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000197
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100198 if (G_filter.flushb) {
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100199 struct nlmsghdr *fn;
200
Denys Vlasenkof1334712011-02-09 04:39:09 +0100201 /* We are creating route flush commands */
202
203 if (r->rtm_family == AF_INET6
204 && r->rtm_dst_len == 0
205 && r->rtm_type == RTN_UNREACHABLE
206 && tb[RTA_PRIORITY]
207 && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
208 ) {
209 return 0;
210 }
211
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100212 if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000213 if (flush_update())
Curt Brune69934702015-10-14 12:53:47 +0200214 xfunc_die();
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000215 }
Denys Vlasenkoe3ece782011-02-10 09:50:07 +0100216 fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000217 memcpy(fn, n, n->nlmsg_len);
218 fn->nlmsg_type = RTM_DELROUTE;
219 fn->nlmsg_flags = NLM_F_REQUEST;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100220 fn->nlmsg_seq = ++G_filter.rth->seq;
221 G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
222 G_filter.flushed = 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000223 return 0;
224 }
225
Denys Vlasenkof1334712011-02-09 04:39:09 +0100226 /* We are printing routes */
227
Glenn L McGrath16528552002-11-28 11:17:19 +0000228 if (n->nlmsg_type == RTM_DELROUTE) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000229 printf("Deleted ");
Glenn L McGrath16528552002-11-28 11:17:19 +0000230 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100231 if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
Denys Vlasenko3d8d5e82015-10-08 13:02:28 +0200232 printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
Glenn L McGrath16528552002-11-28 11:17:19 +0000233 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000234
235 if (tb[RTA_DST]) {
236 if (r->rtm_dst_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200237 printf("%s/%u ",
238 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
239 r->rtm_dst_len
240 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000241 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000242 printf("%s ", format_host(r->rtm_family,
243 RTA_PAYLOAD(tb[RTA_DST]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200244 RTA_DATA(tb[RTA_DST]))
245 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000246 }
247 } else if (r->rtm_dst_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000248 printf("0/%d ", r->rtm_dst_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000249 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000250 printf("default ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000251 }
252 if (tb[RTA_SRC]) {
253 if (r->rtm_src_len != host_len) {
Denys Vlasenko926d8012015-10-14 13:56:42 +0200254 printf("from %s/%u ",
255 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
256 r->rtm_src_len
257 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000258 } else {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000259 printf("from %s ", format_host(r->rtm_family,
260 RTA_PAYLOAD(tb[RTA_SRC]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200261 RTA_DATA(tb[RTA_SRC]))
262 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000263 }
264 } else if (r->rtm_src_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000265 printf("from 0/%u ", r->rtm_src_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000266 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100267 if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000268 printf("via %s ", format_host(r->rtm_family,
269 RTA_PAYLOAD(tb[RTA_GATEWAY]),
Denys Vlasenko926d8012015-10-14 13:56:42 +0200270 RTA_DATA(tb[RTA_GATEWAY]))
271 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000272 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100273 if (tb[RTA_OIF]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000274 printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
Glenn L McGrath16528552002-11-28 11:17:19 +0000275 }
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000276#if ENABLE_FEATURE_IP_RULE
277 if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
278 printf("table %s ", rtnl_rttable_n2a(tid));
279#endif
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000280
André Draszik2f24d302017-06-13 19:59:59 +0200281 /* Todo: parse & show "proto kernel" here */
282 if (!(r->rtm_flags & RTM_F_CLONED)) {
283 if ((r->rtm_scope != RT_SCOPE_UNIVERSE) && G_filter.scopemask != -1)
284 printf("scope %s ", rtnl_rtscope_n2a(r->rtm_scope));
285 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100286
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100287 if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000288 /* Do not use format_host(). It is our local addr
289 and symbolic name will not be useful.
290 */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000291 printf(" src %s ", rt_addr_n2a(r->rtm_family,
Denys Vlasenko926d8012015-10-14 13:56:42 +0200292 RTA_DATA(tb[RTA_PREFSRC])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000293 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000294 if (tb[RTA_PRIORITY]) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000295 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
Glenn L McGrath16528552002-11-28 11:17:19 +0000296 }
Michael Tokarev1a114392014-07-28 10:05:41 +0400297 if (r->rtm_flags & RTNH_F_DEAD) {
298 printf("dead ");
299 }
300 if (r->rtm_flags & RTNH_F_ONLINK) {
301 printf("onlink ");
302 }
303 if (r->rtm_flags & RTNH_F_PERVASIVE) {
304 printf("pervasive ");
305 }
306 if (r->rtm_flags & RTM_F_NOTIFY) {
307 printf("notify ");
308 }
309
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000310 if (r->rtm_family == AF_INET6) {
311 struct rta_cacheinfo *ci = NULL;
Glenn L McGrath16528552002-11-28 11:17:19 +0000312 if (tb[RTA_CACHEINFO]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000313 ci = RTA_DATA(tb[RTA_CACHEINFO]);
Glenn L McGrath16528552002-11-28 11:17:19 +0000314 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000315 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000316 if (r->rtm_flags & RTM_F_CLONED) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000317 printf("%c cache ", _SL_);
Glenn L McGrath16528552002-11-28 11:17:19 +0000318 }
319 if (ci->rta_expires) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000320 printf(" expires %dsec", ci->rta_expires / get_hz());
Glenn L McGrath16528552002-11-28 11:17:19 +0000321 }
322 if (ci->rta_error != 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000323 printf(" error %d", ci->rta_error);
Glenn L McGrath16528552002-11-28 11:17:19 +0000324 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000325 } else if (ci) {
326 if (ci->rta_error != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000327 printf(" error %d", ci->rta_error);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000328 }
329 }
Denys Vlasenkof1334712011-02-09 04:39:09 +0100330 if (tb[RTA_IIF] && G_filter.iif == 0) {
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000331 printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000332 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000333 bb_putchar('\n');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000334 return 0;
335}
336
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200337static int str_is_lock(const char *str)
338{
339 return strcmp(str, "lock") == 0;
340}
341
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000342/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000343static int iproute_modify(int cmd, unsigned flags, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000344{
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200345 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000346 static const char keywords[] ALIGN1 =
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200347 "src\0""via\0"
348 "mtu\0""advmss\0"
349 "scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
Michael Tokarev1a114392014-07-28 10:05:41 +0400350 "dev\0""oif\0""to\0""metric\0""onlink\0";
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200351#define keyword_via (keywords + sizeof("src"))
352#define keyword_mtu (keyword_via + sizeof("via"))
353#define keyword_advmss (keyword_mtu + sizeof("mtu"))
354#define keyword_scope (keyword_advmss + sizeof("advmss"))
355#define keyword_proto (keyword_scope + sizeof("scope"))
356#define keyword_table (keyword_proto + sizeof("protocol"))
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000357 enum {
358 ARG_src,
359 ARG_via,
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200360 ARG_mtu,
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200361 ARG_advmss,
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100362 ARG_scope,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000363 ARG_protocol,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000364IF_FEATURE_IP_RULE(ARG_table,)
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000365 ARG_dev,
366 ARG_oif,
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000367 ARG_to,
368 ARG_metric,
Michael Tokarev1a114392014-07-28 10:05:41 +0400369 ARG_onlink,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000370 };
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000371 enum {
372 gw_ok = 1 << 0,
373 dst_ok = 1 << 1,
374 proto_ok = 1 << 2,
375 type_ok = 1 << 3
376 };
377 struct rtnl_handle rth;
378 struct {
Denys Vlasenkofb132e42010-10-29 11:46:52 +0200379 struct nlmsghdr n;
380 struct rtmsg r;
381 char buf[1024];
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000382 } req;
383 char mxbuf[256];
384 struct rtattr * mxrta = (void*)mxbuf;
385 unsigned mxlock = 0;
386 char *d = NULL;
387 smalluint ok = 0;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100388 smalluint scope_ok = 0;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000389 int arg;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000390
391 memset(&req, 0, sizeof(req));
392
393 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000394 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000395 req.n.nlmsg_type = cmd;
396 req.r.rtm_family = preferred_family;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100397 if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000398 req.r.rtm_table = RT_TABLE_MAIN;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100399 if (RT_SCOPE_NOWHERE != 0)
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000400 req.r.rtm_scope = RT_SCOPE_NOWHERE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000401
402 if (cmd != RTM_DELROUTE) {
Denys Vlasenko34ecc3b2016-08-14 01:30:34 +0200403 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100404 if (RTPROT_BOOT != 0)
405 req.r.rtm_protocol = RTPROT_BOOT;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100406 if (RTN_UNICAST != 0)
407 req.r.rtm_type = RTN_UNICAST;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000408 }
409
410 mxrta->rta_type = RTA_METRICS;
411 mxrta->rta_len = RTA_LENGTH(0);
412
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000413 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000414 arg = index_in_substrings(keywords, *argv);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000415 if (arg == ARG_src) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000416 inet_prefix addr;
417 NEXT_ARG();
418 get_addr(&addr, *argv, req.r.rtm_family);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000419 if (req.r.rtm_family == AF_UNSPEC)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000420 req.r.rtm_family = addr.family;
421 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000422 } else if (arg == ARG_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000423 inet_prefix addr;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000424 ok |= gw_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000425 NEXT_ARG();
426 get_addr(&addr, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000427 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000428 req.r.rtm_family = addr.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000429 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000430 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000431 } else if (arg == ARG_mtu) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000432 unsigned mtu;
433 NEXT_ARG();
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200434 if (str_is_lock(*argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000435 mxlock |= (1 << RTAX_MTU);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000436 NEXT_ARG();
437 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200438 mtu = get_unsigned(*argv, keyword_mtu);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000439 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200440 } else if (arg == ARG_advmss) {
441 unsigned mss;
442 NEXT_ARG();
443 if (str_is_lock(*argv)) {
444 mxlock |= (1 << RTAX_ADVMSS);
445 NEXT_ARG();
446 }
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200447 mss = get_unsigned(*argv, keyword_advmss);
Denys Vlasenkod5342a12017-04-07 17:00:53 +0200448 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100449 } else if (arg == ARG_scope) {
450 uint32_t scope;
451 NEXT_ARG();
452 if (rtnl_rtscope_a2n(&scope, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200453 invarg_1_to_2(*argv, keyword_scope);
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100454 req.r.rtm_scope = scope;
455 scope_ok = 1;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000456 } else if (arg == ARG_protocol) {
Eric Andersend78aea82006-01-30 18:00:02 +0000457 uint32_t prot;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000458 NEXT_ARG();
459 if (rtnl_rtprot_a2n(&prot, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200460 invarg_1_to_2(*argv, keyword_proto);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000461 req.r.rtm_protocol = prot;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000462 ok |= proto_ok;
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000463#if ENABLE_FEATURE_IP_RULE
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000464 } else if (arg == ARG_table) {
Denis Vlasenkocda6c632006-12-15 00:59:35 +0000465 uint32_t tid;
466 NEXT_ARG();
467 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +0200468 invarg_1_to_2(*argv, keyword_table);
Eugene Rudoyecce3a12017-10-19 00:05:11 +0200469#if HAVE_RTA_TABLE
470 if (tid > 255) {
Lukasz Nowakb42107f2016-12-13 12:58:31 +0000471 req.r.rtm_table = RT_TABLE_UNSPEC;
472 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
Eugene Rudoyecce3a12017-10-19 00:05:11 +0200473 } else
474#endif
475 req.r.rtm_table = tid;
Bernhard Reutner-Fischerab51bf42007-04-16 14:56:01 +0000476#endif
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000477 } else if (arg == ARG_dev || arg == ARG_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000478 NEXT_ARG();
479 d = *argv;
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000480 } else if (arg == ARG_metric) {
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200481//TODO: "metric", "priority" and "preference" are synonyms
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000482 uint32_t metric;
483 NEXT_ARG();
Denis Vlasenko76140a72009-03-05 09:21:57 +0000484 metric = get_u32(*argv, "metric");
Bernhard Reutner-Fischer578de862008-10-07 17:00:58 +0000485 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
Michael Tokarev1a114392014-07-28 10:05:41 +0400486 } else if (arg == ARG_onlink) {
487 req.r.rtm_flags |= RTNH_F_ONLINK;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000488 } else {
489 int type;
490 inet_prefix dst;
491
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000492 if (arg == ARG_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000493 NEXT_ARG();
494 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000495 if ((**argv < '0' || **argv > '9')
Denys Vlasenko3bb235c2011-02-23 01:20:44 +0100496 && rtnl_rtntype_a2n(&type, *argv) == 0
497 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000498 NEXT_ARG();
499 req.r.rtm_type = type;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000500 ok |= type_ok;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000501 }
502
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000503 if (ok & dst_ok) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000504 duparg2("to", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000505 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000506 get_prefix(&dst, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000507 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000508 req.r.rtm_family = dst.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000509 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000510 req.r.rtm_dst_len = dst.bitlen;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000511 ok |= dst_ok;
Glenn L McGrath16528552002-11-28 11:17:19 +0000512 if (dst.bytelen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000513 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
Glenn L McGrath16528552002-11-28 11:17:19 +0000514 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000515 }
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200516/* Other keywords recognized by iproute2-3.19.0: */
517#if 0
518 } else if (strcmp(*argv, "from") == 0) {
519 inet_prefix addr;
520 NEXT_ARG();
521 get_prefix(&addr, *argv, req.r.rtm_family);
522 if (req.r.rtm_family == AF_UNSPEC)
523 req.r.rtm_family = addr.family;
524 if (addr.bytelen)
525 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
526 req.r.rtm_src_len = addr.bitlen;
527 } else if (strcmp(*argv, "tos") == 0 ||
528 matches(*argv, "dsfield") == 0) {
529 __u32 tos;
530 NEXT_ARG();
531 if (rtnl_dsfield_a2n(&tos, *argv))
532 invarg("\"tos\" value is invalid\n", *argv);
533 req.r.rtm_tos = tos;
534 } else if (strcmp(*argv, "hoplimit") == 0) {
535 unsigned hoplimit;
536 NEXT_ARG();
537 if (strcmp(*argv, "lock") == 0) {
538 mxlock |= (1<<RTAX_HOPLIMIT);
539 NEXT_ARG();
540 }
541 if (get_unsigned(&hoplimit, *argv, 0))
542 invarg("\"hoplimit\" value is invalid\n", *argv);
543 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
Denys Vlasenko1140bf32017-04-06 17:54:38 +0200544 } else if (matches(*argv, "reordering") == 0) {
545 unsigned reord;
546 NEXT_ARG();
547 if (strcmp(*argv, "lock") == 0) {
548 mxlock |= (1<<RTAX_REORDERING);
549 NEXT_ARG();
550 }
551 if (get_unsigned(&reord, *argv, 0))
552 invarg("\"reordering\" value is invalid\n", *argv);
553 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
554 } else if (strcmp(*argv, "rtt") == 0) {
555 unsigned rtt;
556 NEXT_ARG();
557 if (strcmp(*argv, "lock") == 0) {
558 mxlock |= (1<<RTAX_RTT);
559 NEXT_ARG();
560 }
561 if (get_time_rtt(&rtt, *argv, &raw))
562 invarg("\"rtt\" value is invalid\n", *argv);
563 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
564 (raw) ? rtt : rtt * 8);
565 } else if (strcmp(*argv, "rto_min") == 0) {
566 unsigned rto_min;
567 NEXT_ARG();
568 mxlock |= (1<<RTAX_RTO_MIN);
569 if (get_time_rtt(&rto_min, *argv, &raw))
570 invarg("\"rto_min\" value is invalid\n",
571 *argv);
572 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
573 rto_min);
574 } else if (matches(*argv, "window") == 0) {
575 unsigned win;
576 NEXT_ARG();
577 if (strcmp(*argv, "lock") == 0) {
578 mxlock |= (1<<RTAX_WINDOW);
579 NEXT_ARG();
580 }
581 if (get_unsigned(&win, *argv, 0))
582 invarg("\"window\" value is invalid\n", *argv);
583 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
584 } else if (matches(*argv, "cwnd") == 0) {
585 unsigned win;
586 NEXT_ARG();
587 if (strcmp(*argv, "lock") == 0) {
588 mxlock |= (1<<RTAX_CWND);
589 NEXT_ARG();
590 }
591 if (get_unsigned(&win, *argv, 0))
592 invarg("\"cwnd\" value is invalid\n", *argv);
593 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
594 } else if (matches(*argv, "initcwnd") == 0) {
595 unsigned win;
596 NEXT_ARG();
597 if (strcmp(*argv, "lock") == 0) {
598 mxlock |= (1<<RTAX_INITCWND);
599 NEXT_ARG();
600 }
601 if (get_unsigned(&win, *argv, 0))
602 invarg("\"initcwnd\" value is invalid\n", *argv);
603 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
604 } else if (matches(*argv, "initrwnd") == 0) {
605 unsigned win;
606 NEXT_ARG();
607 if (strcmp(*argv, "lock") == 0) {
608 mxlock |= (1<<RTAX_INITRWND);
609 NEXT_ARG();
610 }
611 if (get_unsigned(&win, *argv, 0))
612 invarg("\"initrwnd\" value is invalid\n", *argv);
613 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
614 } else if (matches(*argv, "features") == 0) {
615 unsigned int features = 0;
616
617 while (argc > 0) {
618 NEXT_ARG();
619
620 if (strcmp(*argv, "ecn") == 0)
621 features |= RTAX_FEATURE_ECN;
622 else
623 invarg("\"features\" value not valid\n", *argv);
624 break;
625 }
626
627 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features);
628 } else if (matches(*argv, "quickack") == 0) {
629 unsigned quickack;
630 NEXT_ARG();
631 if (get_unsigned(&quickack, *argv, 0))
632 invarg("\"quickack\" value is invalid\n", *argv);
633 if (quickack != 1 && quickack != 0)
634 invarg("\"quickack\" value should be 0 or 1\n", *argv);
635 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
636 } else if (matches(*argv, "rttvar") == 0) {
637 unsigned win;
638 NEXT_ARG();
639 if (strcmp(*argv, "lock") == 0) {
640 mxlock |= (1<<RTAX_RTTVAR);
641 NEXT_ARG();
642 }
643 if (get_time_rtt(&win, *argv, &raw))
644 invarg("\"rttvar\" value is invalid\n", *argv);
645 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
646 (raw) ? win : win * 4);
647 } else if (matches(*argv, "ssthresh") == 0) {
648 unsigned win;
649 NEXT_ARG();
650 if (strcmp(*argv, "lock") == 0) {
651 mxlock |= (1<<RTAX_SSTHRESH);
652 NEXT_ARG();
653 }
654 if (get_unsigned(&win, *argv, 0))
655 invarg("\"ssthresh\" value is invalid\n", *argv);
656 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
657 } else if (matches(*argv, "realms") == 0) {
658 __u32 realm;
659 NEXT_ARG();
660 if (get_rt_realms(&realm, *argv))
661 invarg("\"realm\" value is invalid\n", *argv);
662 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
663 } else if (strcmp(*argv, "nexthop") == 0) {
664 nhs_ok = 1;
665 break;
666 }
667#endif
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000668 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000669 }
670
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000671 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000672
Eric Andersen5780adb2002-11-15 09:12:47 +0000673 if (d) {
674 int idx;
675
676 ll_init_map(&rth);
677
678 if (d) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000679 idx = xll_name_to_index(d);
Eric Andersen5780adb2002-11-15 09:12:47 +0000680 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
681 }
682 }
683
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000684 if (mxrta->rta_len > RTA_LENGTH(0)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000685 if (mxlock) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000686 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
Glenn L McGrath16528552002-11-28 11:17:19 +0000687 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000688 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
689 }
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000690
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100691 if (!scope_ok) {
692 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
693 req.r.rtm_scope = RT_SCOPE_HOST;
694 else
695 if (req.r.rtm_type == RTN_BROADCAST
696 || req.r.rtm_type == RTN_MULTICAST
697 || req.r.rtm_type == RTN_ANYCAST
698 ) {
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000699 req.r.rtm_scope = RT_SCOPE_LINK;
Denys Vlasenkoce4bc1e2015-12-30 17:32:51 +0100700 }
701 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
702 if (cmd == RTM_DELROUTE)
703 req.r.rtm_scope = RT_SCOPE_NOWHERE;
704 else if (!(ok & gw_ok))
705 req.r.rtm_scope = RT_SCOPE_LINK;
706 }
Bernhard Reutner-Fischer12c96a62007-04-11 16:23:57 +0000707 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000708
Glenn L McGrath16528552002-11-28 11:17:19 +0000709 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000710 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000711 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000712
Glenn L McGrath16528552002-11-28 11:17:19 +0000713 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000714 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +0000715 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000716
717 return 0;
718}
719
720static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
721{
722 struct {
723 struct nlmsghdr nlh;
724 struct rtmsg rtm;
725 } req;
726 struct sockaddr_nl nladdr;
727
728 memset(&nladdr, 0, sizeof(nladdr));
729 memset(&req, 0, sizeof(req));
730 nladdr.nl_family = AF_NETLINK;
731
732 req.nlh.nlmsg_len = sizeof(req);
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000733 if (RTM_GETROUTE)
734 req.nlh.nlmsg_type = RTM_GETROUTE;
735 if (NLM_F_ROOT | NLM_F_REQUEST)
736 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
737 /*req.nlh.nlmsg_pid = 0; - memset did it already */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000738 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
739 req.rtm.rtm_family = family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000740 if (RTM_F_CLONED)
741 req.rtm.rtm_flags = RTM_F_CLONED;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000742
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000743 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000744}
745
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000746static void iproute_flush_cache(void)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000747{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000748 static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000749 int flush_fd = open_or_warn(fn, O_WRONLY);
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000750
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000751 if (flush_fd < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000752 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000753 }
754
Denis Vlasenko89ef65f2007-01-29 23:43:18 +0000755 if (write(flush_fd, "-1", 2) < 2) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100756 bb_perror_msg("can't flush routing cache");
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000757 return;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000758 }
759 close(flush_fd);
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000760}
761
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000762static void iproute_reset_filter(void)
763{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100764 memset(&G_filter, 0, sizeof(G_filter));
765 G_filter.mdst.bitlen = -1;
766 G_filter.msrc.bitlen = -1;
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000767}
768
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000769/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000770static int iproute_list_or_flush(char **argv, int flush)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000771{
772 int do_ipv6 = preferred_family;
773 struct rtnl_handle rth;
774 char *id = NULL;
775 char *od = NULL;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000776 static const char keywords[] ALIGN1 =
André Draszik2f24d302017-06-13 19:59:59 +0200777 /* If you add stuff here, update iproute_full_usage */
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000778 /* "ip route list/flush" parameters: */
779 "protocol\0" "dev\0" "oif\0" "iif\0"
780 "via\0" "table\0" "cache\0"
André Draszik2f24d302017-06-13 19:59:59 +0200781 "from\0" "to\0" "scope\0"
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000782 /* and possible further keywords */
783 "all\0"
784 "root\0"
785 "match\0"
786 "exact\0"
787 "main\0"
788 ;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000789 enum {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000790 KW_proto, KW_dev, KW_oif, KW_iif,
791 KW_via, KW_table, KW_cache,
André Draszik2f24d302017-06-13 19:59:59 +0200792 KW_from, KW_to, KW_scope,
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000793 /* */
794 KW_all,
795 KW_root,
796 KW_match,
797 KW_exact,
798 KW_main,
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000799 };
800 int arg, parm;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000801
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000802 iproute_reset_filter();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100803 G_filter.tb = RT_TABLE_MAIN;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000804
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000805 if (flush && !*argv)
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000806 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000807
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000808 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000809 arg = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000810 if (arg == KW_proto) {
Eric Andersend78aea82006-01-30 18:00:02 +0000811 uint32_t prot = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000812 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100813 //G_filter.protocolmask = -1;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000814 if (rtnl_rtprot_a2n(&prot, *argv)) {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000815 if (index_in_strings(keywords, *argv) != KW_all)
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200816 invarg_1_to_2(*argv, "protocol");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000817 prot = 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100818 //G_filter.protocolmask = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000819 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100820 //G_filter.protocol = prot;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000821 } else if (arg == KW_dev || arg == KW_oif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000822 NEXT_ARG();
823 od = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000824 } else if (arg == KW_iif) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000825 NEXT_ARG();
826 id = *argv;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000827 } else if (arg == KW_via) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000828 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100829 get_prefix(&G_filter.rvia, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000830 } else if (arg == KW_table) { /* table all/cache/main */
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000831 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000832 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000833 if (parm == KW_cache)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100834 G_filter.tb = -1;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000835 else if (parm == KW_all)
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100836 G_filter.tb = 0;
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000837 else if (parm != KW_main) {
838#if ENABLE_FEATURE_IP_RULE
839 uint32_t tid;
840 if (rtnl_rttable_a2n(&tid, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200841 invarg_1_to_2(*argv, "table");
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100842 G_filter.tb = tid;
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000843#else
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200844 invarg_1_to_2(*argv, "table");
Denis Vlasenko52a8d972008-06-08 00:25:55 +0000845#endif
846 }
Denis Vlasenko79c69042007-11-27 09:42:33 +0000847 } else if (arg == KW_cache) {
848 /* The command 'ip route flush cache' is used by OpenSWAN.
849 * Assuming it's a synonym for 'ip route flush table cache' */
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100850 G_filter.tb = -1;
André Draszik2f24d302017-06-13 19:59:59 +0200851 } else if (arg == KW_scope) {
852 uint32_t scope;
853 NEXT_ARG();
854 G_filter.scopemask = -1;
855 if (rtnl_rtscope_a2n(&scope, *argv)) {
856 if (strcmp(*argv, "all") != 0)
857 invarg_1_to_2(*argv, "scope");
858 scope = RT_SCOPE_NOWHERE;
859 G_filter.scopemask = 0;
860 }
861 G_filter.scope = scope;
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000862 } else if (arg == KW_from) {
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000863 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000864 parm = index_in_substrings(keywords, *argv);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000865 if (parm == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000866 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100867 get_prefix(&G_filter.rsrc, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000868 } else if (parm == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000869 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100870 get_prefix(&G_filter.msrc, *argv, do_ipv6);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000871 } else {
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000872 if (parm == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000873 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100874 get_prefix(&G_filter.msrc, *argv, do_ipv6);
875 G_filter.rsrc = G_filter.msrc;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000876 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000877 } else { /* "to" is the default parameter */
878 if (arg == KW_to) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000879 NEXT_ARG();
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000880 arg = index_in_substrings(keywords, *argv);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000881 }
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000882 /* parm = arg; - would be more plausible, but we reuse 'arg' here */
883 if (arg == KW_root) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000884 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100885 get_prefix(&G_filter.rdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000886 } else if (arg == KW_match) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000887 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100888 get_prefix(&G_filter.mdst, *argv, do_ipv6);
Denis Vlasenko186c2b32007-11-26 18:29:52 +0000889 } else { /* "to exact" is the default */
890 if (arg == KW_exact)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000891 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100892 get_prefix(&G_filter.mdst, *argv, do_ipv6);
893 G_filter.rdst = G_filter.mdst;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000894 }
895 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000896 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000897 }
898
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100899 if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000900 do_ipv6 = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000901 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000902
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000903 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000904 ll_init_map(&rth);
905
906 if (id || od) {
907 int idx;
908
909 if (id) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000910 idx = xll_name_to_index(id);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100911 G_filter.iif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000912 }
913 if (od) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000914 idx = xll_name_to_index(od);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100915 G_filter.oif = idx;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000916 }
917 }
918
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000919 if (flush) {
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000920 char flushb[4096-512];
921
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100922 if (G_filter.tb == -1) { /* "flush table cache" */
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000923 if (do_ipv6 != AF_INET6)
924 iproute_flush_cache();
925 if (do_ipv6 == AF_INET)
926 return 0;
927 }
928
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100929 G_filter.flushb = flushb;
930 G_filter.flushp = 0;
931 G_filter.flushe = sizeof(flushb);
932 G_filter.rth = &rth;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000933
934 for (;;) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000935 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100936 G_filter.flushed = 0;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000937 xrtnl_dump_filter(&rth, print_route, NULL);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100938 if (G_filter.flushed == 0)
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000939 return 0;
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000940 if (flush_update())
941 return 1;
Glenn L McGrath4a4c6772003-02-15 11:50:33 +0000942 }
943 }
944
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100945 if (G_filter.tb != -1) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000946 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000947 } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100948 bb_perror_msg_and_die("can't send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000949 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000950 xrtnl_dump_filter(&rth, print_route, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000951
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000952 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000953}
954
955
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000956/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000957static int iproute_get(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000958{
959 struct rtnl_handle rth;
960 struct {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000961 struct nlmsghdr n;
962 struct rtmsg r;
963 char buf[1024];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000964 } req;
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000965 char *idev = NULL;
966 char *odev = NULL;
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +0000967 bool connected = 0;
968 bool from_ok = 0;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000969 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000970 "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000971
972 memset(&req, 0, sizeof(req));
973
974 iproute_reset_filter();
975
976 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000977 if (NLM_F_REQUEST)
978 req.n.nlmsg_flags = NLM_F_REQUEST;
979 if (RTM_GETROUTE)
980 req.n.nlmsg_type = RTM_GETROUTE;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000981 req.r.rtm_family = preferred_family;
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +0000982 /*req.r.rtm_table = 0; - memset did this already */
983 /*req.r.rtm_protocol = 0;*/
984 /*req.r.rtm_scope = 0;*/
985 /*req.r.rtm_type = 0;*/
986 /*req.r.rtm_src_len = 0;*/
987 /*req.r.rtm_dst_len = 0;*/
988 /*req.r.rtm_tos = 0;*/
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000989
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000990 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000991 switch (index_in_strings(options, *argv)) {
Glenn L McGrath18eae002002-12-02 00:54:10 +0000992 case 0: /* from */
993 {
994 inet_prefix addr;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000995 NEXT_ARG();
Glenn L McGrath18eae002002-12-02 00:54:10 +0000996 from_ok = 1;
997 get_prefix(&addr, *argv, req.r.rtm_family);
998 if (req.r.rtm_family == AF_UNSPEC) {
999 req.r.rtm_family = addr.family;
1000 }
1001 if (addr.bytelen) {
1002 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
1003 }
1004 req.r.rtm_src_len = addr.bitlen;
1005 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001006 }
Glenn L McGrath18eae002002-12-02 00:54:10 +00001007 case 1: /* iif */
1008 NEXT_ARG();
1009 idev = *argv;
1010 break;
1011 case 2: /* oif */
1012 case 3: /* dev */
1013 NEXT_ARG();
1014 odev = *argv;
1015 break;
1016 case 4: /* notify */
1017 req.r.rtm_flags |= RTM_F_NOTIFY;
1018 break;
1019 case 5: /* connected */
1020 connected = 1;
1021 break;
1022 case 6: /* to */
1023 NEXT_ARG();
1024 default:
1025 {
1026 inet_prefix addr;
1027 get_prefix(&addr, *argv, req.r.rtm_family);
1028 if (req.r.rtm_family == AF_UNSPEC) {
1029 req.r.rtm_family = addr.family;
1030 }
1031 if (addr.bytelen) {
1032 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
1033 }
1034 req.r.rtm_dst_len = addr.bitlen;
1035 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001036 }
Christian Hornung3bbfb582010-11-03 14:08:00 +01001037 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001038 }
1039
1040 if (req.r.rtm_dst_len == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001041 bb_error_msg_and_die("need at least destination address");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001042 }
1043
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001044 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001045
1046 ll_init_map(&rth);
1047
1048 if (idev || odev) {
1049 int idx;
1050
1051 if (idev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001052 idx = xll_name_to_index(idev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001053 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1054 }
1055 if (odev) {
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +00001056 idx = xll_name_to_index(odev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001057 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1058 }
1059 }
1060
Glenn L McGrath16528552002-11-28 11:17:19 +00001061 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001062 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +00001063 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001064
Glenn L McGrath16528552002-11-28 11:17:19 +00001065 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001066 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001067 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001068
1069 if (connected && !from_ok) {
1070 struct rtmsg *r = NLMSG_DATA(&req.n);
1071 int len = req.n.nlmsg_len;
1072 struct rtattr * tb[RTA_MAX+1];
1073
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001074 print_route(NULL, &req.n, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001075
1076 if (req.n.nlmsg_type != RTM_NEWROUTE) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001077 bb_error_msg_and_die("not a route?");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001078 }
1079 len -= NLMSG_LENGTH(sizeof(*r));
1080 if (len < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001081 bb_error_msg_and_die("wrong len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001082 }
1083
Denys Vlasenko68ae5422018-02-08 08:42:37 +01001084 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001085 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1086
1087 if (tb[RTA_PREFSRC]) {
1088 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1089 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1090 } else if (!tb[RTA_SRC]) {
Denys Vlasenko651a2692010-03-23 16:25:17 +01001091 bb_error_msg_and_die("can't connect the route");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001092 }
Glenn L McGrath16528552002-11-28 11:17:19 +00001093 if (!odev && tb[RTA_OIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001094 tb[RTA_OIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001095 }
1096 if (tb[RTA_GATEWAY]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001097 tb[RTA_GATEWAY]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001098 }
1099 if (!idev && tb[RTA_IIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001100 tb[RTA_IIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +00001101 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001102 req.n.nlmsg_flags = NLM_F_REQUEST;
1103 req.n.nlmsg_type = RTM_GETROUTE;
1104
Glenn L McGrath16528552002-11-28 11:17:19 +00001105 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001106 return 2;
Glenn L McGrath16528552002-11-28 11:17:19 +00001107 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001108 }
Denis Vlasenko0db2c2e2008-06-29 06:22:40 +00001109 print_route(NULL, &req.n, NULL);
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001110 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001111}
1112
Denis Vlasenko540a2a12007-04-07 01:14:45 +00001113/* Return value becomes exitcode. It's okay to not return at all */
Denys Vlasenko2e9b5512010-07-24 23:27:38 +02001114int FAST_FUNC do_iproute(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001115{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001116 static const char ip_route_commands[] ALIGN1 =
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001117 "a\0""add\0""append\0""change\0""chg\0"
1118 "delete\0""get\0""list\0""show\0"
1119 "prepend\0""replace\0""test\0""flush\0"
1120 ;
1121 enum {
1122 CMD_a = 0, CMD_add, CMD_append, CMD_change, CMD_chg,
1123 CMD_delete, CMD_get, CMD_list, CMD_show,
1124 CMD_prepend, CMD_replace, CMD_test, CMD_flush,
1125 };
Denis Vlasenko83c44222008-01-04 15:28:28 +00001126 int command_num;
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001127 unsigned flags = 0;
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001128 int cmd = RTM_NEWROUTE;
1129
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +02001130 INIT_G();
1131
Denis Vlasenko83c44222008-01-04 15:28:28 +00001132 if (!*argv)
1133 return iproute_list_or_flush(argv, 0);
1134
Denis Vlasenko5af906e2006-11-05 18:05:09 +00001135 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
1136 /* It probably means that it is using "first match" rule */
Denis Vlasenko83c44222008-01-04 15:28:28 +00001137 command_num = index_in_substrings(ip_route_commands, *argv);
1138
Denis Vlasenkoc16bd212006-09-27 19:51:06 +00001139 switch (command_num) {
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001140 case CMD_a:
1141 case CMD_add:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001142 flags = NLM_F_CREATE|NLM_F_EXCL;
1143 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001144 case CMD_append:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001145 flags = NLM_F_CREATE|NLM_F_APPEND;
1146 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001147 case CMD_change:
1148 case CMD_chg:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001149 flags = NLM_F_REPLACE;
1150 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001151 case CMD_delete:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001152 cmd = RTM_DELROUTE;
1153 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001154 case CMD_get:
1155 return iproute_get(argv + 1);
1156 case CMD_list:
1157 case CMD_show:
1158 return iproute_list_or_flush(argv + 1, 0);
1159 case CMD_prepend:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001160 flags = NLM_F_CREATE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001161 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001162 case CMD_replace:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001163 flags = NLM_F_CREATE|NLM_F_REPLACE;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001164 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001165 case CMD_test:
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001166 flags = NLM_F_EXCL;
Denis Vlasenko1eecaf22007-09-30 16:04:21 +00001167 break;
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001168 case CMD_flush:
1169 return iproute_list_or_flush(argv + 1, 1);
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001170 default:
Denys Vlasenko0f296a32015-10-14 13:21:01 +02001171 invarg_1_to_2(*argv, applet_name);
Glenn L McGrath16528552002-11-28 11:17:19 +00001172 }
Glenn L McGrathc82f2322002-12-02 00:35:23 +00001173
Denys Vlasenkoeb76abb2017-04-07 17:33:26 +02001174 return iproute_modify(cmd, flags, argv + 1);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001175}