1/*
2 * iproute.c		"ip route".
3 *
4 *		This program is free software; you can redistribute it and/or
5 *		modify it under the terms of the GNU General Public License
6 *		as published by the Free Software Foundation; either version
7 *		2 of the License, or (at your option) any later version.
8 *
9 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
18#include <string.h>
19#include <time.h>
20#include <sys/time.h>
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <netinet/ip.h>
24#include <arpa/inet.h>
25#include <linux/in_route.h>
26#include <linux/icmpv6.h>
27#include <errno.h>
28
29#include "rt_names.h"
30#include "utils.h"
31#include "ip_common.h"
32#include "iproute_lwtunnel.h"
33
34#ifndef RTAX_RTTVAR
35#define RTAX_RTTVAR RTAX_HOPS
36#endif
37
38enum list_action {
39	IPROUTE_LIST,
40	IPROUTE_FLUSH,
41	IPROUTE_SAVE,
42};
43static const char *mx_names[RTAX_MAX+1] = {
44	[RTAX_MTU]	= "mtu",
45	[RTAX_WINDOW]	= "window",
46	[RTAX_RTT]	= "rtt",
47	[RTAX_RTTVAR]	= "rttvar",
48	[RTAX_SSTHRESH] = "ssthresh",
49	[RTAX_CWND]	= "cwnd",
50	[RTAX_ADVMSS]	= "advmss",
51	[RTAX_REORDERING]="reordering",
52	[RTAX_HOPLIMIT] = "hoplimit",
53	[RTAX_INITCWND] = "initcwnd",
54	[RTAX_FEATURES] = "features",
55	[RTAX_RTO_MIN]	= "rto_min",
56	[RTAX_INITRWND]	= "initrwnd",
57	[RTAX_QUICKACK]	= "quickack",
58	[RTAX_CC_ALGO]	= "congctl",
59};
60static void usage(void) __attribute__((noreturn));
61
62static void usage(void)
63{
64	fprintf(stderr, "Usage: ip route { list | flush } SELECTOR\n");
65	fprintf(stderr, "       ip route save SELECTOR\n");
66	fprintf(stderr, "       ip route restore\n");
67	fprintf(stderr, "       ip route showdump\n");
68	fprintf(stderr, "       ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
69	fprintf(stderr, "                            [ oif STRING ] [ tos TOS ]\n");
70	fprintf(stderr, "                            [ mark NUMBER ] [ uid NUMBER ]\n");
71	fprintf(stderr, "       ip route { add | del | change | append | replace } ROUTE\n");
72	fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
73	fprintf(stderr, "            [ table TABLE_ID ] [ proto RTPROTO ]\n");
74	fprintf(stderr, "            [ type TYPE ] [ scope SCOPE ]\n");
75	fprintf(stderr, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n");
76	fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
77	fprintf(stderr, "             [ table TABLE_ID ] [ proto RTPROTO ]\n");
78	fprintf(stderr, "             [ scope SCOPE ] [ metric METRIC ]\n");
79	fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
80	fprintf(stderr, "NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n");
81	fprintf(stderr, "	    [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
82	fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n");
83	fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n");
84	fprintf(stderr, "           [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n");
85	fprintf(stderr, "           [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
86	fprintf(stderr, "           [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
87	fprintf(stderr, "           [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n");
88	fprintf(stderr, "           [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n");
89	fprintf(stderr, "           [ pref PREF ] [ expires TIME ]\n");
90	fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
91	fprintf(stderr, "          unreachable | prohibit | blackhole | nat ]\n");
92	fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
93	fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n");
94	fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
95	fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
96	fprintf(stderr, "PREF := [ low | medium | high ]\n");
97	fprintf(stderr, "TIME := NUMBER[s|ms]\n");
98	fprintf(stderr, "BOOL := [1|0]\n");
99	fprintf(stderr, "FEATURES := ecn\n");
100	fprintf(stderr, "ENCAPTYPE := [ mpls | ip | ip6 ]\n");
101	fprintf(stderr, "ENCAPHDR := [ MPLSLABEL ]\n");
102	exit(-1);
103}
104
105
106static struct
107{
108	unsigned int tb;
109	int cloned;
110	int flushed;
111	char *flushb;
112	int flushp;
113	int flushe;
114	int protocol, protocolmask;
115	int scope, scopemask;
116	int type, typemask;
117	int tos, tosmask;
118	int iif, iifmask;
119	int oif, oifmask;
120	int mark, markmask;
121	int realm, realmmask;
122	inet_prefix rprefsrc;
123	inet_prefix rvia;
124	inet_prefix rdst;
125	inet_prefix mdst;
126	inet_prefix rsrc;
127	inet_prefix msrc;
128} filter;
129
130static int flush_update(void)
131{
132	if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
133		perror("Failed to send flush request");
134		return -1;
135	}
136	filter.flushp = 0;
137	return 0;
138}
139
140static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
141{
142	struct rtmsg *r = NLMSG_DATA(n);
143	inet_prefix dst;
144	inet_prefix src;
145	inet_prefix via;
146	inet_prefix prefsrc;
147	__u32 table;
148	static int ip6_multiple_tables;
149
150	table = rtm_get_table(r, tb);
151
152	if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
153		return 0;
154
155	if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
156		ip6_multiple_tables = 1;
157
158	if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
159		return 0;
160
161	if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
162		if (filter.tb) {
163			if (filter.tb == RT_TABLE_LOCAL) {
164				if (r->rtm_type != RTN_LOCAL)
165					return 0;
166			} else if (filter.tb == RT_TABLE_MAIN) {
167				if (r->rtm_type == RTN_LOCAL)
168					return 0;
169			} else {
170				return 0;
171			}
172		}
173	} else {
174		if (filter.tb > 0 && filter.tb != table)
175			return 0;
176	}
177	if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
178		return 0;
179	if ((filter.scope^r->rtm_scope)&filter.scopemask)
180		return 0;
181	if ((filter.type^r->rtm_type)&filter.typemask)
182		return 0;
183	if ((filter.tos^r->rtm_tos)&filter.tosmask)
184		return 0;
185	if (filter.rdst.family &&
186	    (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
187		return 0;
188	if (filter.mdst.family &&
189	    (r->rtm_family != filter.mdst.family ||
190	     (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
191		return 0;
192	if (filter.rsrc.family &&
193	    (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
194		return 0;
195	if (filter.msrc.family &&
196	    (r->rtm_family != filter.msrc.family ||
197	     (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
198		return 0;
199	if (filter.rvia.family) {
200		int family = r->rtm_family;
201		if (tb[RTA_VIA]) {
202			struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
203			family = via->rtvia_family;
204		}
205		if (family != filter.rvia.family)
206			return 0;
207	}
208	if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
209		return 0;
210
211	memset(&dst, 0, sizeof(dst));
212	dst.family = r->rtm_family;
213	if (tb[RTA_DST])
214		memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8);
215	if (filter.rsrc.family || filter.msrc.family) {
216		memset(&src, 0, sizeof(src));
217		src.family = r->rtm_family;
218		if (tb[RTA_SRC])
219			memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8);
220	}
221	if (filter.rvia.bitlen>0) {
222		memset(&via, 0, sizeof(via));
223		via.family = r->rtm_family;
224		if (tb[RTA_GATEWAY])
225			memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
226		if (tb[RTA_VIA]) {
227			size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
228			struct rtvia *rtvia = RTA_DATA(tb[RTA_VIA]);
229			via.family = rtvia->rtvia_family;
230			memcpy(&via.data, rtvia->rtvia_addr, len);
231		}
232	}
233	if (filter.rprefsrc.bitlen>0) {
234		memset(&prefsrc, 0, sizeof(prefsrc));
235		prefsrc.family = r->rtm_family;
236		if (tb[RTA_PREFSRC])
237			memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
238	}
239
240	if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
241		return 0;
242	if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
243	    inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
244		return 0;
245
246	if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
247		return 0;
248	if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
249	    inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
250		return 0;
251
252	if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen))
253		return 0;
254	if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen))
255		return 0;
256	if (filter.realmmask) {
257		__u32 realms = 0;
258		if (tb[RTA_FLOW])
259			realms = rta_getattr_u32(tb[RTA_FLOW]);
260		if ((realms^filter.realm)&filter.realmmask)
261			return 0;
262	}
263	if (filter.iifmask) {
264		int iif = 0;
265		if (tb[RTA_IIF])
266			iif = *(int*)RTA_DATA(tb[RTA_IIF]);
267		if ((iif^filter.iif)&filter.iifmask)
268			return 0;
269	}
270	if (filter.oifmask) {
271		int oif = 0;
272		if (tb[RTA_OIF])
273			oif = *(int*)RTA_DATA(tb[RTA_OIF]);
274		if ((oif^filter.oif)&filter.oifmask)
275			return 0;
276	}
277	if (filter.markmask) {
278		int mark = 0;
279		if (tb[RTA_MARK])
280			mark = *(int *)RTA_DATA(tb[RTA_MARK]);
281		if ((mark ^ filter.mark) & filter.markmask)
282			return 0;
283	}
284	if (filter.flushb &&
285	    r->rtm_family == AF_INET6 &&
286	    r->rtm_dst_len == 0 &&
287	    r->rtm_type == RTN_UNREACHABLE &&
288	    tb[RTA_PRIORITY] &&
289	    *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
290		return 0;
291
292	return 1;
293}
294
295static void print_rtax_features(FILE *fp, unsigned int features)
296{
297	unsigned int of = features;
298
299	if (features & RTAX_FEATURE_ECN) {
300		fprintf(fp, " ecn");
301		features &= ~RTAX_FEATURE_ECN;
302	}
303
304	if (features)
305		fprintf(fp, " 0x%x", of);
306}
307
308int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
309{
310	FILE *fp = (FILE*)arg;
311	struct rtmsg *r = NLMSG_DATA(n);
312	int len = n->nlmsg_len;
313	struct rtattr * tb[RTA_MAX+1];
314	char abuf[256];
315	int host_len;
316	__u32 table;
317	SPRINT_BUF(b1);
318	static int hz;
319
320	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
321		fprintf(stderr, "Not a route: %08x %08x %08x\n",
322			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
323		return 0;
324	}
325	if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
326		return 0;
327	len -= NLMSG_LENGTH(sizeof(*r));
328	if (len < 0) {
329		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
330		return -1;
331	}
332
333	host_len = af_bit_len(r->rtm_family);
334
335	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
336	table = rtm_get_table(r, tb);
337
338	if (!filter_nlmsg(n, tb, host_len))
339		return 0;
340
341	if (filter.flushb) {
342		struct nlmsghdr *fn;
343		if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
344			if (flush_update())
345				return -1;
346		}
347		fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
348		memcpy(fn, n, n->nlmsg_len);
349		fn->nlmsg_type = RTM_DELROUTE;
350		fn->nlmsg_flags = NLM_F_REQUEST;
351		fn->nlmsg_seq = ++rth.seq;
352		filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
353		filter.flushed++;
354		if (show_stats < 2)
355			return 0;
356	}
357
358	if (n->nlmsg_type == RTM_DELROUTE)
359		fprintf(fp, "Deleted ");
360	if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type)
361		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
362
363	if (tb[RTA_DST]) {
364		if (r->rtm_dst_len != host_len) {
365			fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
366						       RTA_PAYLOAD(tb[RTA_DST]),
367						       RTA_DATA(tb[RTA_DST]),
368						       abuf, sizeof(abuf)),
369				r->rtm_dst_len
370				);
371		} else {
372			fprintf(fp, "%s ", format_host(r->rtm_family,
373						       RTA_PAYLOAD(tb[RTA_DST]),
374						       RTA_DATA(tb[RTA_DST]),
375						       abuf, sizeof(abuf))
376				);
377		}
378	} else if (r->rtm_dst_len) {
379		fprintf(fp, "0/%d ", r->rtm_dst_len);
380	} else {
381		fprintf(fp, "default ");
382	}
383	if (tb[RTA_SRC]) {
384		if (r->rtm_src_len != host_len) {
385			fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
386						       RTA_PAYLOAD(tb[RTA_SRC]),
387						       RTA_DATA(tb[RTA_SRC]),
388						       abuf, sizeof(abuf)),
389				r->rtm_src_len
390				);
391		} else {
392			fprintf(fp, "from %s ", format_host(r->rtm_family,
393						       RTA_PAYLOAD(tb[RTA_SRC]),
394						       RTA_DATA(tb[RTA_SRC]),
395						       abuf, sizeof(abuf))
396				);
397		}
398	} else if (r->rtm_src_len) {
399		fprintf(fp, "from 0/%u ", r->rtm_src_len);
400	}
401	if (tb[RTA_NEWDST]) {
402		fprintf(fp, "as to %s ", format_host(r->rtm_family,
403						  RTA_PAYLOAD(tb[RTA_NEWDST]),
404						  RTA_DATA(tb[RTA_NEWDST]),
405						  abuf, sizeof(abuf))
406			);
407	}
408
409	if (tb[RTA_ENCAP])
410		lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
411
412	if (r->rtm_tos && filter.tosmask != -1) {
413		SPRINT_BUF(b1);
414		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
415	}
416
417	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
418		fprintf(fp, "via %s ",
419			format_host(r->rtm_family,
420				    RTA_PAYLOAD(tb[RTA_GATEWAY]),
421				    RTA_DATA(tb[RTA_GATEWAY]),
422				    abuf, sizeof(abuf)));
423	}
424	if (tb[RTA_VIA]) {
425		size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
426		struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
427		fprintf(fp, "via %s %s ",
428			family_name(via->rtvia_family),
429			format_host(via->rtvia_family, len, via->rtvia_addr,
430				    abuf, sizeof(abuf)));
431	}
432	if (tb[RTA_OIF] && filter.oifmask != -1)
433		fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
434
435	if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
436		fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
437	if (!(r->rtm_flags&RTM_F_CLONED)) {
438		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
439			fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
440		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
441			fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
442	}
443	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
444		/* Do not use format_host(). It is our local addr
445		   and symbolic name will not be useful.
446		 */
447		fprintf(fp, " src %s ",
448			rt_addr_n2a(r->rtm_family,
449				    RTA_PAYLOAD(tb[RTA_PREFSRC]),
450				    RTA_DATA(tb[RTA_PREFSRC]),
451				    abuf, sizeof(abuf)));
452	}
453	if (tb[RTA_PRIORITY])
454		fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
455	if (r->rtm_flags & RTNH_F_DEAD)
456		fprintf(fp, "dead ");
457	if (r->rtm_flags & RTNH_F_ONLINK)
458		fprintf(fp, "onlink ");
459	if (r->rtm_flags & RTNH_F_PERVASIVE)
460		fprintf(fp, "pervasive ");
461	if (r->rtm_flags & RTNH_F_OFFLOAD)
462		fprintf(fp, "offload ");
463	if (r->rtm_flags & RTM_F_NOTIFY)
464		fprintf(fp, "notify ");
465	if (r->rtm_flags & RTNH_F_LINKDOWN)
466		fprintf(fp, "linkdown ");
467	if (tb[RTA_MARK]) {
468		unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]);
469		if (mark) {
470			if (mark >= 16)
471				fprintf(fp, " mark 0x%x", mark);
472			else
473				fprintf(fp, " mark %u", mark);
474		}
475	}
476
477	if (tb[RTA_UID])
478		fprintf(fp, " uid %u ", rta_getattr_u32(tb[RTA_UID]));
479
480	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
481		__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
482		__u32 from = to>>16;
483		to &= 0xFFFF;
484		fprintf(fp, "realm%s ", from ? "s" : "");
485		if (from) {
486			fprintf(fp, "%s/",
487				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
488		}
489		fprintf(fp, "%s ",
490			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
491	}
492	if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
493		__u32 flags = r->rtm_flags&~0xFFFF;
494		int first = 1;
495
496		fprintf(fp, "%s    cache ", _SL_);
497
498#define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
499  flags &= ~RTCF_##fl; \
500  fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
501  first = 0; }
502		PRTFL(LOCAL, "local");
503		PRTFL(REJECT, "reject");
504		PRTFL(MULTICAST, "mc");
505		PRTFL(BROADCAST, "brd");
506		PRTFL(DNAT, "dst-nat");
507		PRTFL(SNAT, "src-nat");
508		PRTFL(MASQ, "masq");
509		PRTFL(DIRECTDST, "dst-direct");
510		PRTFL(DIRECTSRC, "src-direct");
511		PRTFL(REDIRECTED, "redirected");
512		PRTFL(DOREDIRECT, "redirect");
513		PRTFL(FAST, "fastroute");
514		PRTFL(NOTIFY, "notify");
515		PRTFL(TPROXY, "proxy");
516
517		if (flags)
518			fprintf(fp, "%s%x> ", first ? "<" : "", flags);
519		if (tb[RTA_CACHEINFO]) {
520			struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
521			if (!hz)
522				hz = get_user_hz();
523			if (ci->rta_expires != 0)
524				fprintf(fp, " expires %dsec", ci->rta_expires/hz);
525			if (ci->rta_error != 0)
526				fprintf(fp, " error %d", ci->rta_error);
527			if (show_stats) {
528				if (ci->rta_clntref)
529					fprintf(fp, " users %d", ci->rta_clntref);
530				if (ci->rta_used != 0)
531					fprintf(fp, " used %d", ci->rta_used);
532				if (ci->rta_lastuse != 0)
533					fprintf(fp, " age %dsec", ci->rta_lastuse/hz);
534			}
535			if (ci->rta_id)
536				fprintf(fp, " ipid 0x%04x", ci->rta_id);
537			if (ci->rta_ts || ci->rta_tsage)
538				fprintf(fp, " ts 0x%x tsage %dsec",
539					ci->rta_ts, ci->rta_tsage);
540		}
541	} else if (r->rtm_family == AF_INET6) {
542		struct rta_cacheinfo *ci = NULL;
543		if (tb[RTA_CACHEINFO])
544			ci = RTA_DATA(tb[RTA_CACHEINFO]);
545		if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
546			if (!hz)
547				hz = get_user_hz();
548			if (r->rtm_flags & RTM_F_CLONED)
549				fprintf(fp, "%s    cache ", _SL_);
550			if (ci->rta_expires)
551				fprintf(fp, " expires %dsec", ci->rta_expires/hz);
552			if (ci->rta_error != 0)
553				fprintf(fp, " error %d", ci->rta_error);
554			if (show_stats) {
555				if (ci->rta_clntref)
556					fprintf(fp, " users %d", ci->rta_clntref);
557				if (ci->rta_used != 0)
558					fprintf(fp, " used %d", ci->rta_used);
559				if (ci->rta_lastuse != 0)
560					fprintf(fp, " age %dsec", ci->rta_lastuse/hz);
561			}
562		} else if (ci) {
563			if (ci->rta_error != 0)
564				fprintf(fp, " error %d", ci->rta_error);
565		}
566	}
567	if (tb[RTA_METRICS]) {
568		int i;
569		unsigned mxlock = 0;
570		struct rtattr *mxrta[RTAX_MAX+1];
571
572		parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
573			    RTA_PAYLOAD(tb[RTA_METRICS]));
574		if (mxrta[RTAX_LOCK])
575			mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]);
576
577		for (i=2; i<= RTAX_MAX; i++) {
578			__u32 val;
579
580			if (mxrta[i] == NULL)
581				continue;
582
583			if (i != RTAX_CC_ALGO)
584				val = rta_getattr_u32(mxrta[i]);
585
586			if (i == RTAX_HOPLIMIT && (int)val == -1)
587				continue;
588
589			if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i])
590				fprintf(fp, " %s", mx_names[i]);
591			else
592				fprintf(fp, " metric %d", i);
593
594			if (mxlock & (1<<i))
595				fprintf(fp, " lock");
596
597			switch (i) {
598			case RTAX_FEATURES:
599				print_rtax_features(fp, val);
600				break;
601			default:
602				fprintf(fp, " %u", val);
603				break;
604
605			case RTAX_RTT:
606			case RTAX_RTTVAR:
607			case RTAX_RTO_MIN:
608				if (i == RTAX_RTT)
609					val /= 8;
610				else if (i == RTAX_RTTVAR)
611					val /= 4;
612
613				if (val >= 1000)
614					fprintf(fp, " %gs", val/1e3);
615				else
616					fprintf(fp, " %ums", val);
617				break;
618			case RTAX_CC_ALGO:
619				fprintf(fp, " %s", rta_getattr_str(mxrta[i]));
620				break;
621			}
622		}
623	}
624	if (tb[RTA_IIF] && filter.iifmask != -1) {
625		fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
626	}
627	if (tb[RTA_MULTIPATH]) {
628		struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
629		int first = 0;
630
631		len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
632
633		for (;;) {
634			if (len < sizeof(*nh))
635				break;
636			if (nh->rtnh_len > len)
637				break;
638			if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
639				if (first)
640					fprintf(fp, " Oifs:");
641				else
642					fprintf(fp, " ");
643			} else
644				fprintf(fp, "%s\tnexthop", _SL_);
645			if (nh->rtnh_len > sizeof(*nh)) {
646				parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
647
648				if (tb[RTA_ENCAP])
649					lwt_print_encap(fp,
650							tb[RTA_ENCAP_TYPE],
651							tb[RTA_ENCAP]);
652
653				if (tb[RTA_GATEWAY]) {
654					fprintf(fp, " via %s ",
655						format_host(r->rtm_family,
656							    RTA_PAYLOAD(tb[RTA_GATEWAY]),
657							    RTA_DATA(tb[RTA_GATEWAY]),
658							    abuf, sizeof(abuf)));
659				}
660				if (tb[RTA_VIA]) {
661					size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
662					struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
663					fprintf(fp, "via %s %s ",
664						family_name(via->rtvia_family),
665						format_host(via->rtvia_family, len, via->rtvia_addr,
666							    abuf, sizeof(abuf)));
667				}
668				if (tb[RTA_FLOW]) {
669					__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
670					__u32 from = to>>16;
671					to &= 0xFFFF;
672					fprintf(fp, " realm%s ", from ? "s" : "");
673					if (from) {
674						fprintf(fp, "%s/",
675							rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
676					}
677					fprintf(fp, "%s",
678						rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
679				}
680			}
681			if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
682				fprintf(fp, " %s", ll_index_to_name(nh->rtnh_ifindex));
683				if (nh->rtnh_hops != 1)
684					fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
685			} else {
686				fprintf(fp, " dev %s", ll_index_to_name(nh->rtnh_ifindex));
687				fprintf(fp, " weight %d", nh->rtnh_hops+1);
688			}
689			if (nh->rtnh_flags & RTNH_F_DEAD)
690				fprintf(fp, " dead");
691			if (nh->rtnh_flags & RTNH_F_ONLINK)
692				fprintf(fp, " onlink");
693			if (nh->rtnh_flags & RTNH_F_PERVASIVE)
694				fprintf(fp, " pervasive");
695			if (nh->rtnh_flags & RTNH_F_LINKDOWN)
696				fprintf(fp, " linkdown");
697			len -= NLMSG_ALIGN(nh->rtnh_len);
698			nh = RTNH_NEXT(nh);
699		}
700	}
701	if (tb[RTA_PREF]) {
702		unsigned int pref = rta_getattr_u8(tb[RTA_PREF]);
703		fprintf(fp, " pref ");
704
705		switch (pref) {
706		case ICMPV6_ROUTER_PREF_LOW:
707			fprintf(fp, "low");
708			break;
709		case ICMPV6_ROUTER_PREF_MEDIUM:
710			fprintf(fp, "medium");
711			break;
712		case ICMPV6_ROUTER_PREF_HIGH:
713			fprintf(fp, "high");
714			break;
715		default:
716			fprintf(fp, "%u", pref);
717		}
718	}
719	fprintf(fp, "\n");
720	fflush(fp);
721	return 0;
722}
723
724static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
725			struct rtattr *rta, struct rtnexthop *rtnh,
726			int *argcp, char ***argvp)
727{
728	int argc = *argcp;
729	char **argv = *argvp;
730
731	while (++argv, --argc > 0) {
732		if (strcmp(*argv, "via") == 0) {
733			inet_prefix addr;
734			int family;
735			NEXT_ARG();
736			family = read_family(*argv);
737			if (family == AF_UNSPEC)
738				family = r->rtm_family;
739			else
740				NEXT_ARG();
741			get_addr(&addr, *argv, family);
742			if (r->rtm_family == AF_UNSPEC)
743				r->rtm_family = addr.family;
744			if (addr.family == r->rtm_family) {
745				rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
746				rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
747			} else {
748				rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
749				rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen+2;
750			}
751		} else if (strcmp(*argv, "dev") == 0) {
752			NEXT_ARG();
753			if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
754				fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
755				exit(1);
756			}
757		} else if (strcmp(*argv, "weight") == 0) {
758			unsigned w;
759			NEXT_ARG();
760			if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256)
761				invarg("\"weight\" is invalid\n", *argv);
762			rtnh->rtnh_hops = w - 1;
763		} else if (strcmp(*argv, "onlink") == 0) {
764			rtnh->rtnh_flags |= RTNH_F_ONLINK;
765		} else if (matches(*argv, "realms") == 0) {
766			__u32 realm;
767			NEXT_ARG();
768			if (get_rt_realms_or_raw(&realm, *argv))
769				invarg("\"realm\" value is invalid\n", *argv);
770			rta_addattr32(rta, 4096, RTA_FLOW, realm);
771			rtnh->rtnh_len += sizeof(struct rtattr) + 4;
772		} else if (strcmp(*argv, "encap") == 0) {
773			int len = rta->rta_len;
774
775			lwt_parse_encap(rta, 4096, &argc, &argv);
776			rtnh->rtnh_len += rta->rta_len - len;
777		} else
778			break;
779	}
780	*argcp = argc;
781	*argvp = argv;
782	return 0;
783}
784
785static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
786			  int argc, char **argv)
787{
788	char buf[1024];
789	struct rtattr *rta = (void*)buf;
790	struct rtnexthop *rtnh;
791
792	rta->rta_type = RTA_MULTIPATH;
793	rta->rta_len = RTA_LENGTH(0);
794	rtnh = RTA_DATA(rta);
795
796	while (argc > 0) {
797		if (strcmp(*argv, "nexthop") != 0) {
798			fprintf(stderr, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv);
799			exit(-1);
800		}
801		if (argc <= 1) {
802			fprintf(stderr, "Error: unexpected end of line after \"nexthop\"\n");
803			exit(-1);
804		}
805		memset(rtnh, 0, sizeof(*rtnh));
806		rtnh->rtnh_len = sizeof(*rtnh);
807		rta->rta_len += rtnh->rtnh_len;
808		parse_one_nh(n, r, rta, rtnh, &argc, &argv);
809		rtnh = RTNH_NEXT(rtnh);
810	}
811
812	if (rta->rta_len > RTA_LENGTH(0))
813		addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
814	return 0;
815}
816
817static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
818{
819	struct {
820		struct nlmsghdr	n;
821		struct rtmsg		r;
822		char  			buf[1024];
823	} req;
824	char  mxbuf[256];
825	struct rtattr * mxrta = (void*)mxbuf;
826	unsigned mxlock = 0;
827	char  *d = NULL;
828	int gw_ok = 0;
829	int dst_ok = 0;
830	int nhs_ok = 0;
831	int scope_ok = 0;
832	int table_ok = 0;
833	int raw = 0;
834	int type_ok = 0;
835	static int hz;
836
837	memset(&req, 0, sizeof(req));
838
839	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
840	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
841	req.n.nlmsg_type = cmd;
842	req.r.rtm_family = preferred_family;
843	req.r.rtm_table = RT_TABLE_MAIN;
844	req.r.rtm_scope = RT_SCOPE_NOWHERE;
845
846	if (cmd != RTM_DELROUTE) {
847		req.r.rtm_protocol = RTPROT_BOOT;
848		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
849		req.r.rtm_type = RTN_UNICAST;
850	}
851
852	mxrta->rta_type = RTA_METRICS;
853	mxrta->rta_len = RTA_LENGTH(0);
854
855	while (argc > 0) {
856		if (strcmp(*argv, "src") == 0) {
857			inet_prefix addr;
858			NEXT_ARG();
859			get_addr(&addr, *argv, req.r.rtm_family);
860			if (req.r.rtm_family == AF_UNSPEC)
861				req.r.rtm_family = addr.family;
862			addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
863		} else if (strcmp(*argv, "as") == 0) {
864			inet_prefix addr;
865			NEXT_ARG();
866			if (strcmp(*argv, "to") == 0) {
867				NEXT_ARG();
868			}
869			get_addr(&addr, *argv, req.r.rtm_family);
870			if (req.r.rtm_family == AF_UNSPEC)
871				req.r.rtm_family = addr.family;
872			addattr_l(&req.n, sizeof(req), RTA_NEWDST, &addr.data, addr.bytelen);
873		} else if (strcmp(*argv, "via") == 0) {
874			inet_prefix addr;
875			int family;
876			gw_ok = 1;
877			NEXT_ARG();
878			family = read_family(*argv);
879			if (family == AF_UNSPEC)
880				family = req.r.rtm_family;
881			else
882				NEXT_ARG();
883			get_addr(&addr, *argv, family);
884			if (req.r.rtm_family == AF_UNSPEC)
885				req.r.rtm_family = addr.family;
886			if (addr.family == req.r.rtm_family)
887				addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
888			else
889				addattr_l(&req.n, sizeof(req), RTA_VIA, &addr.family, addr.bytelen+2);
890		} else if (strcmp(*argv, "from") == 0) {
891			inet_prefix addr;
892			NEXT_ARG();
893			get_prefix(&addr, *argv, req.r.rtm_family);
894			if (req.r.rtm_family == AF_UNSPEC)
895				req.r.rtm_family = addr.family;
896			if (addr.bytelen)
897				addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
898			req.r.rtm_src_len = addr.bitlen;
899		} else if (strcmp(*argv, "tos") == 0 ||
900			   matches(*argv, "dsfield") == 0) {
901			__u32 tos;
902			NEXT_ARG();
903			if (rtnl_dsfield_a2n(&tos, *argv))
904				invarg("\"tos\" value is invalid\n", *argv);
905			req.r.rtm_tos = tos;
906		} else if (strcmp(*argv, "expires") == 0 ) {
907			__u32 expires;
908			NEXT_ARG();
909			if (get_u32(&expires, *argv, 0))
910				invarg("\"expires\" value is invalid\n", *argv);
911			if (!hz)
912				hz = get_user_hz();
913			addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires*hz);
914		} else if (matches(*argv, "metric") == 0 ||
915			   matches(*argv, "priority") == 0 ||
916			   strcmp(*argv, "preference") == 0) {
917			__u32 metric;
918			NEXT_ARG();
919			if (get_u32(&metric, *argv, 0))
920				invarg("\"metric\" value is invalid\n", *argv);
921			addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
922		} else if (strcmp(*argv, "scope") == 0) {
923			__u32 scope = 0;
924			NEXT_ARG();
925			if (rtnl_rtscope_a2n(&scope, *argv))
926				invarg("invalid \"scope\" value\n", *argv);
927			req.r.rtm_scope = scope;
928			scope_ok = 1;
929		} else if (strcmp(*argv, "mtu") == 0) {
930			unsigned mtu;
931			NEXT_ARG();
932			if (strcmp(*argv, "lock") == 0) {
933				mxlock |= (1<<RTAX_MTU);
934				NEXT_ARG();
935			}
936			if (get_unsigned(&mtu, *argv, 0))
937				invarg("\"mtu\" value is invalid\n", *argv);
938			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
939		} else if (strcmp(*argv, "hoplimit") == 0) {
940			unsigned hoplimit;
941			NEXT_ARG();
942			if (strcmp(*argv, "lock") == 0) {
943				mxlock |= (1<<RTAX_HOPLIMIT);
944				NEXT_ARG();
945			}
946			if (get_unsigned(&hoplimit, *argv, 0) || hoplimit > 255)
947				invarg("\"hoplimit\" value is invalid\n", *argv);
948			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
949		} else if (strcmp(*argv, "advmss") == 0) {
950			unsigned mss;
951			NEXT_ARG();
952			if (strcmp(*argv, "lock") == 0) {
953				mxlock |= (1<<RTAX_ADVMSS);
954				NEXT_ARG();
955			}
956			if (get_unsigned(&mss, *argv, 0))
957				invarg("\"mss\" value is invalid\n", *argv);
958			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
959		} else if (matches(*argv, "reordering") == 0) {
960			unsigned reord;
961			NEXT_ARG();
962			if (strcmp(*argv, "lock") == 0) {
963				mxlock |= (1<<RTAX_REORDERING);
964				NEXT_ARG();
965			}
966			if (get_unsigned(&reord, *argv, 0))
967				invarg("\"reordering\" value is invalid\n", *argv);
968			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
969		} else if (strcmp(*argv, "rtt") == 0) {
970			unsigned rtt;
971			NEXT_ARG();
972			if (strcmp(*argv, "lock") == 0) {
973				mxlock |= (1<<RTAX_RTT);
974				NEXT_ARG();
975			}
976			if (get_time_rtt(&rtt, *argv, &raw))
977				invarg("\"rtt\" value is invalid\n", *argv);
978			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
979				(raw) ? rtt : rtt * 8);
980		} else if (strcmp(*argv, "rto_min") == 0) {
981			unsigned rto_min;
982			NEXT_ARG();
983			mxlock |= (1<<RTAX_RTO_MIN);
984			if (get_time_rtt(&rto_min, *argv, &raw))
985				invarg("\"rto_min\" value is invalid\n",
986				       *argv);
987			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
988				      rto_min);
989		} else if (matches(*argv, "window") == 0) {
990			unsigned win;
991			NEXT_ARG();
992			if (strcmp(*argv, "lock") == 0) {
993				mxlock |= (1<<RTAX_WINDOW);
994				NEXT_ARG();
995			}
996			if (get_unsigned(&win, *argv, 0))
997				invarg("\"window\" value is invalid\n", *argv);
998			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
999		} else if (matches(*argv, "cwnd") == 0) {
1000			unsigned win;
1001			NEXT_ARG();
1002			if (strcmp(*argv, "lock") == 0) {
1003				mxlock |= (1<<RTAX_CWND);
1004				NEXT_ARG();
1005			}
1006			if (get_unsigned(&win, *argv, 0))
1007				invarg("\"cwnd\" value is invalid\n", *argv);
1008			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
1009		} else if (matches(*argv, "initcwnd") == 0) {
1010			unsigned win;
1011			NEXT_ARG();
1012			if (strcmp(*argv, "lock") == 0) {
1013				mxlock |= (1<<RTAX_INITCWND);
1014				NEXT_ARG();
1015			}
1016			if (get_unsigned(&win, *argv, 0))
1017				invarg("\"initcwnd\" value is invalid\n", *argv);
1018			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
1019		} else if (matches(*argv, "initrwnd") == 0) {
1020			unsigned win;
1021			NEXT_ARG();
1022			if (strcmp(*argv, "lock") == 0) {
1023				mxlock |= (1<<RTAX_INITRWND);
1024				NEXT_ARG();
1025			}
1026			if (get_unsigned(&win, *argv, 0))
1027				invarg("\"initrwnd\" value is invalid\n", *argv);
1028			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
1029		} else if (matches(*argv, "features") == 0) {
1030			unsigned int features = 0;
1031
1032			while (argc > 0) {
1033				NEXT_ARG();
1034
1035				if (strcmp(*argv, "ecn") == 0)
1036					features |= RTAX_FEATURE_ECN;
1037				else
1038					invarg("\"features\" value not valid\n", *argv);
1039				break;
1040			}
1041
1042			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features);
1043		} else if (matches(*argv, "quickack") == 0) {
1044			unsigned quickack;
1045			NEXT_ARG();
1046			if (get_unsigned(&quickack, *argv, 0))
1047				invarg("\"quickack\" value is invalid\n", *argv);
1048			if (quickack != 1 && quickack != 0)
1049				invarg("\"quickack\" value should be 0 or 1\n", *argv);
1050			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
1051		} else if (matches(*argv, "congctl") == 0) {
1052			NEXT_ARG();
1053			if (strcmp(*argv, "lock") == 0) {
1054				mxlock |= 1 << RTAX_CC_ALGO;
1055				NEXT_ARG();
1056			}
1057			rta_addattr_l(mxrta, sizeof(mxbuf), RTAX_CC_ALGO, *argv,
1058				      strlen(*argv));
1059		} else if (matches(*argv, "rttvar") == 0) {
1060			unsigned win;
1061			NEXT_ARG();
1062			if (strcmp(*argv, "lock") == 0) {
1063				mxlock |= (1<<RTAX_RTTVAR);
1064				NEXT_ARG();
1065			}
1066			if (get_time_rtt(&win, *argv, &raw))
1067				invarg("\"rttvar\" value is invalid\n", *argv);
1068			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
1069				(raw) ? win : win * 4);
1070		} else if (matches(*argv, "ssthresh") == 0) {
1071			unsigned win;
1072			NEXT_ARG();
1073			if (strcmp(*argv, "lock") == 0) {
1074				mxlock |= (1<<RTAX_SSTHRESH);
1075				NEXT_ARG();
1076			}
1077			if (get_unsigned(&win, *argv, 0))
1078				invarg("\"ssthresh\" value is invalid\n", *argv);
1079			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
1080		} else if (matches(*argv, "realms") == 0) {
1081			__u32 realm;
1082			NEXT_ARG();
1083			if (get_rt_realms_or_raw(&realm, *argv))
1084				invarg("\"realm\" value is invalid\n", *argv);
1085			addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
1086		} else if (strcmp(*argv, "onlink") == 0) {
1087			req.r.rtm_flags |= RTNH_F_ONLINK;
1088		} else if (strcmp(*argv, "nexthop") == 0) {
1089			nhs_ok = 1;
1090			break;
1091		} else if (matches(*argv, "protocol") == 0) {
1092			__u32 prot;
1093			NEXT_ARG();
1094			if (rtnl_rtprot_a2n(&prot, *argv))
1095				invarg("\"protocol\" value is invalid\n", *argv);
1096			req.r.rtm_protocol = prot;
1097		} else if (matches(*argv, "table") == 0) {
1098			__u32 tid;
1099			NEXT_ARG();
1100			if (rtnl_rttable_a2n(&tid, *argv))
1101				invarg("\"table\" value is invalid\n", *argv);
1102			if (tid < 256)
1103				req.r.rtm_table = tid;
1104			else {
1105				req.r.rtm_table = RT_TABLE_UNSPEC;
1106				addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
1107			}
1108			table_ok = 1;
1109		} else if (strcmp(*argv, "dev") == 0 ||
1110			   strcmp(*argv, "oif") == 0) {
1111			NEXT_ARG();
1112			d = *argv;
1113		} else if (matches(*argv, "pref") == 0) {
1114			__u8 pref;
1115			NEXT_ARG();
1116			if (strcmp(*argv, "low") == 0)
1117				pref = ICMPV6_ROUTER_PREF_LOW;
1118			else if (strcmp(*argv, "medium") == 0)
1119				pref = ICMPV6_ROUTER_PREF_MEDIUM;
1120			else if (strcmp(*argv, "high") == 0)
1121				pref = ICMPV6_ROUTER_PREF_HIGH;
1122			else if (get_u8(&pref, *argv, 0))
1123				invarg("\"pref\" value is invalid\n", *argv);
1124			addattr8(&req.n, sizeof(req), RTA_PREF, pref);
1125		} else if (strcmp(*argv, "encap") == 0) {
1126			char buf[1024];
1127			struct rtattr *rta = (void*)buf;
1128
1129			rta->rta_type = RTA_ENCAP;
1130			rta->rta_len = RTA_LENGTH(0);
1131
1132			lwt_parse_encap(rta, sizeof(buf), &argc, &argv);
1133
1134			if (rta->rta_len > RTA_LENGTH(0))
1135				addraw_l(&req.n, 1024, RTA_DATA(rta), RTA_PAYLOAD(rta));
1136		} else {
1137			int type;
1138			inet_prefix dst;
1139
1140			if (strcmp(*argv, "to") == 0) {
1141				NEXT_ARG();
1142			}
1143			if ((**argv < '0' || **argv > '9') &&
1144			    rtnl_rtntype_a2n(&type, *argv) == 0) {
1145				NEXT_ARG();
1146				req.r.rtm_type = type;
1147				type_ok = 1;
1148			}
1149
1150			if (matches(*argv, "help") == 0)
1151				usage();
1152			if (dst_ok)
1153				duparg2("to", *argv);
1154			get_prefix(&dst, *argv, req.r.rtm_family);
1155			if (req.r.rtm_family == AF_UNSPEC)
1156				req.r.rtm_family = dst.family;
1157			req.r.rtm_dst_len = dst.bitlen;
1158			dst_ok = 1;
1159			if (dst.bytelen)
1160				addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
1161		}
1162		argc--; argv++;
1163	}
1164
1165	if (!dst_ok)
1166		usage();
1167
1168	if (d || nhs_ok)  {
1169		int idx;
1170
1171		if (d) {
1172			if ((idx = ll_name_to_index(d)) == 0) {
1173				fprintf(stderr, "Cannot find device \"%s\"\n", d);
1174				return -1;
1175			}
1176			addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1177		}
1178	}
1179
1180	if (mxrta->rta_len > RTA_LENGTH(0)) {
1181		if (mxlock)
1182			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
1183		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
1184	}
1185
1186	if (nhs_ok)
1187		parse_nexthops(&req.n, &req.r, argc, argv);
1188
1189	if (req.r.rtm_family == AF_UNSPEC)
1190		req.r.rtm_family = AF_INET;
1191
1192	if (!table_ok) {
1193		if (req.r.rtm_type == RTN_LOCAL ||
1194		    req.r.rtm_type == RTN_BROADCAST ||
1195		    req.r.rtm_type == RTN_NAT ||
1196		    req.r.rtm_type == RTN_ANYCAST)
1197			req.r.rtm_table = RT_TABLE_LOCAL;
1198	}
1199	if (!scope_ok) {
1200		if (req.r.rtm_family == AF_INET6 ||
1201		    req.r.rtm_family == AF_MPLS)
1202			req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1203		else if (req.r.rtm_type == RTN_LOCAL ||
1204			 req.r.rtm_type == RTN_NAT)
1205			req.r.rtm_scope = RT_SCOPE_HOST;
1206		else if (req.r.rtm_type == RTN_BROADCAST ||
1207			 req.r.rtm_type == RTN_MULTICAST ||
1208			 req.r.rtm_type == RTN_ANYCAST)
1209			req.r.rtm_scope = RT_SCOPE_LINK;
1210		else if (req.r.rtm_type == RTN_UNICAST ||
1211			 req.r.rtm_type == RTN_UNSPEC) {
1212			if (cmd == RTM_DELROUTE)
1213				req.r.rtm_scope = RT_SCOPE_NOWHERE;
1214			else if (!gw_ok && !nhs_ok)
1215				req.r.rtm_scope = RT_SCOPE_LINK;
1216		}
1217	}
1218
1219	if (!type_ok && req.r.rtm_family == AF_MPLS)
1220		req.r.rtm_type = RTN_UNICAST;
1221
1222	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
1223		return -2;
1224
1225	return 0;
1226}
1227
1228static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
1229{
1230	struct {
1231		struct nlmsghdr nlh;
1232		struct rtmsg rtm;
1233	} req;
1234	struct sockaddr_nl nladdr;
1235
1236	memset(&nladdr, 0, sizeof(nladdr));
1237	memset(&req, 0, sizeof(req));
1238	nladdr.nl_family = AF_NETLINK;
1239
1240	req.nlh.nlmsg_len = sizeof(req);
1241	req.nlh.nlmsg_type = RTM_GETROUTE;
1242	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
1243	req.nlh.nlmsg_pid = 0;
1244	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
1245	req.rtm.rtm_family = family;
1246	req.rtm.rtm_flags |= RTM_F_CLONED;
1247
1248	return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
1249}
1250
1251static int iproute_flush_cache(void)
1252{
1253#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
1254
1255	int len;
1256	int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY);
1257	char *buffer = "-1";
1258
1259	if (flush_fd < 0) {
1260		fprintf (stderr, "Cannot open \"%s\": %s\n",
1261				ROUTE_FLUSH_PATH, strerror(errno));
1262		return -1;
1263	}
1264
1265	len = strlen (buffer);
1266
1267	if ((write (flush_fd, (void *)buffer, len)) < len) {
1268		fprintf (stderr, "Cannot flush routing cache\n");
1269		close(flush_fd);
1270		return -1;
1271	}
1272	close(flush_fd);
1273	return 0;
1274}
1275
1276static __u32 route_dump_magic = 0x45311224;
1277
1278static int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n,
1279		      void *arg)
1280{
1281	int ret;
1282	int len = n->nlmsg_len;
1283	struct rtmsg *r = NLMSG_DATA(n);
1284	struct rtattr *tb[RTA_MAX+1];
1285	int host_len;
1286
1287	host_len = af_bit_len(r->rtm_family);
1288	len -= NLMSG_LENGTH(sizeof(*r));
1289	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1290
1291	if (!filter_nlmsg(n, tb, host_len))
1292		return 0;
1293
1294	ret = write(STDOUT_FILENO, n, n->nlmsg_len);
1295	if ((ret > 0) && (ret != n->nlmsg_len)) {
1296		fprintf(stderr, "Short write while saving nlmsg\n");
1297		ret = -EIO;
1298	}
1299
1300	return ret == n->nlmsg_len ? 0 : ret;
1301}
1302
1303static int save_route_prep(void)
1304{
1305	int ret;
1306
1307	if (isatty(STDOUT_FILENO)) {
1308		fprintf(stderr, "Not sending a binary stream to stdout\n");
1309		return -1;
1310	}
1311
1312	ret = write(STDOUT_FILENO, &route_dump_magic, sizeof(route_dump_magic));
1313	if (ret != sizeof(route_dump_magic)) {
1314		fprintf(stderr, "Can't write magic to dump file\n");
1315		return -1;
1316	}
1317
1318	return 0;
1319}
1320
1321static int iproute_list_flush_or_save(int argc, char **argv, int action)
1322{
1323	int do_ipv6 = preferred_family;
1324	char *id = NULL;
1325	char *od = NULL;
1326	unsigned int mark = 0;
1327	rtnl_filter_t filter_fn;
1328
1329	if (action == IPROUTE_SAVE) {
1330		if (save_route_prep())
1331			return -1;
1332
1333		filter_fn = save_route;
1334	} else
1335		filter_fn = print_route;
1336
1337	iproute_reset_filter(0);
1338	filter.tb = RT_TABLE_MAIN;
1339
1340	if ((action == IPROUTE_FLUSH) && argc <= 0) {
1341		fprintf(stderr, "\"ip route flush\" requires arguments.\n");
1342		return -1;
1343	}
1344
1345	while (argc > 0) {
1346		if (matches(*argv, "table") == 0) {
1347			__u32 tid;
1348			NEXT_ARG();
1349			if (rtnl_rttable_a2n(&tid, *argv)) {
1350				if (strcmp(*argv, "all") == 0) {
1351					filter.tb = 0;
1352				} else if (strcmp(*argv, "cache") == 0) {
1353					filter.cloned = 1;
1354				} else if (strcmp(*argv, "help") == 0) {
1355					usage();
1356				} else {
1357					invarg("table id value is invalid\n", *argv);
1358				}
1359			} else
1360				filter.tb = tid;
1361		} else if (matches(*argv, "cached") == 0 ||
1362			   matches(*argv, "cloned") == 0) {
1363			filter.cloned = 1;
1364		} else if (strcmp(*argv, "tos") == 0 ||
1365			   matches(*argv, "dsfield") == 0) {
1366			__u32 tos;
1367			NEXT_ARG();
1368			if (rtnl_dsfield_a2n(&tos, *argv))
1369				invarg("TOS value is invalid\n", *argv);
1370			filter.tos = tos;
1371			filter.tosmask = -1;
1372		} else if (matches(*argv, "protocol") == 0) {
1373			__u32 prot = 0;
1374			NEXT_ARG();
1375			filter.protocolmask = -1;
1376			if (rtnl_rtprot_a2n(&prot, *argv)) {
1377				if (strcmp(*argv, "all") != 0)
1378					invarg("invalid \"protocol\"\n", *argv);
1379				prot = 0;
1380				filter.protocolmask = 0;
1381			}
1382			filter.protocol = prot;
1383		} else if (matches(*argv, "scope") == 0) {
1384			__u32 scope = 0;
1385			NEXT_ARG();
1386			filter.scopemask = -1;
1387			if (rtnl_rtscope_a2n(&scope, *argv)) {
1388				if (strcmp(*argv, "all") != 0)
1389					invarg("invalid \"scope\"\n", *argv);
1390				scope = RT_SCOPE_NOWHERE;
1391				filter.scopemask = 0;
1392			}
1393			filter.scope = scope;
1394		} else if (matches(*argv, "type") == 0) {
1395			int type;
1396			NEXT_ARG();
1397			filter.typemask = -1;
1398			if (rtnl_rtntype_a2n(&type, *argv))
1399				invarg("node type value is invalid\n", *argv);
1400			filter.type = type;
1401		} else if (strcmp(*argv, "dev") == 0 ||
1402			   strcmp(*argv, "oif") == 0) {
1403			NEXT_ARG();
1404			od = *argv;
1405		} else if (strcmp(*argv, "iif") == 0) {
1406			NEXT_ARG();
1407			id = *argv;
1408		} else if (strcmp(*argv, "mark") == 0) {
1409			NEXT_ARG();
1410			get_unsigned(&mark, *argv, 0);
1411			filter.markmask = -1;
1412		} else if (strcmp(*argv, "via") == 0) {
1413			int family;
1414			NEXT_ARG();
1415			family = read_family(*argv);
1416			if (family == AF_UNSPEC)
1417				family = do_ipv6;
1418			else
1419				NEXT_ARG();
1420			get_prefix(&filter.rvia, *argv, family);
1421		} else if (strcmp(*argv, "src") == 0) {
1422			NEXT_ARG();
1423			get_prefix(&filter.rprefsrc, *argv, do_ipv6);
1424		} else if (matches(*argv, "realms") == 0) {
1425			__u32 realm;
1426			NEXT_ARG();
1427			if (get_rt_realms_or_raw(&realm, *argv))
1428				invarg("invalid realms\n", *argv);
1429			filter.realm = realm;
1430			filter.realmmask = ~0U;
1431			if ((filter.realm&0xFFFF) == 0 &&
1432			    (*argv)[strlen(*argv) - 1] == '/')
1433				filter.realmmask &= ~0xFFFF;
1434			if ((filter.realm&0xFFFF0000U) == 0 &&
1435			    (strchr(*argv, '/') == NULL ||
1436			     (*argv)[0] == '/'))
1437				filter.realmmask &= ~0xFFFF0000U;
1438		} else if (matches(*argv, "from") == 0) {
1439			NEXT_ARG();
1440			if (matches(*argv, "root") == 0) {
1441				NEXT_ARG();
1442				get_prefix(&filter.rsrc, *argv, do_ipv6);
1443			} else if (matches(*argv, "match") == 0) {
1444				NEXT_ARG();
1445				get_prefix(&filter.msrc, *argv, do_ipv6);
1446			} else {
1447				if (matches(*argv, "exact") == 0) {
1448					NEXT_ARG();
1449				}
1450				get_prefix(&filter.msrc, *argv, do_ipv6);
1451				filter.rsrc = filter.msrc;
1452			}
1453		} else {
1454			if (matches(*argv, "to") == 0) {
1455				NEXT_ARG();
1456			}
1457			if (matches(*argv, "root") == 0) {
1458				NEXT_ARG();
1459				get_prefix(&filter.rdst, *argv, do_ipv6);
1460			} else if (matches(*argv, "match") == 0) {
1461				NEXT_ARG();
1462				get_prefix(&filter.mdst, *argv, do_ipv6);
1463			} else {
1464				if (matches(*argv, "exact") == 0) {
1465					NEXT_ARG();
1466				}
1467				get_prefix(&filter.mdst, *argv, do_ipv6);
1468				filter.rdst = filter.mdst;
1469			}
1470		}
1471		argc--; argv++;
1472	}
1473
1474	if (do_ipv6 == AF_UNSPEC && filter.tb)
1475		do_ipv6 = AF_INET;
1476
1477	if (id || od)  {
1478		int idx;
1479
1480		if (id) {
1481			if ((idx = ll_name_to_index(id)) == 0) {
1482				fprintf(stderr, "Cannot find device \"%s\"\n", id);
1483				return -1;
1484			}
1485			filter.iif = idx;
1486			filter.iifmask = -1;
1487		}
1488		if (od) {
1489			if ((idx = ll_name_to_index(od)) == 0) {
1490				fprintf(stderr, "Cannot find device \"%s\"\n", od);
1491				return -1;
1492			}
1493			filter.oif = idx;
1494			filter.oifmask = -1;
1495		}
1496	}
1497	filter.mark = mark;
1498
1499	if (action == IPROUTE_FLUSH) {
1500		int round = 0;
1501		char flushb[4096-512];
1502		time_t start = time(0);
1503
1504		if (filter.cloned) {
1505			if (do_ipv6 != AF_INET6) {
1506				iproute_flush_cache();
1507				if (show_stats)
1508					printf("*** IPv4 routing cache is flushed.\n");
1509			}
1510			if (do_ipv6 == AF_INET)
1511				return 0;
1512		}
1513
1514		filter.flushb = flushb;
1515		filter.flushp = 0;
1516		filter.flushe = sizeof(flushb);
1517
1518		for (;;) {
1519			if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1520				perror("Cannot send dump request");
1521				exit(1);
1522			}
1523			filter.flushed = 0;
1524			if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1525				fprintf(stderr, "Flush terminated\n");
1526				exit(1);
1527			}
1528			if (filter.flushed == 0) {
1529				if (show_stats) {
1530					if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
1531						printf("Nothing to flush.\n");
1532					else
1533						printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
1534				}
1535				fflush(stdout);
1536				return 0;
1537			}
1538			round++;
1539			if (flush_update() < 0)
1540				exit(1);
1541
1542			if (time(0) - start > 30) {
1543				printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1544				       (long)(time(0) - start), filter.flushed);
1545				exit(1);
1546			}
1547
1548			if (show_stats) {
1549				printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
1550				fflush(stdout);
1551			}
1552		}
1553	}
1554
1555	if (!filter.cloned) {
1556		if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1557			perror("Cannot send dump request");
1558			exit(1);
1559		}
1560	} else {
1561		if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
1562			perror("Cannot send dump request");
1563			exit(1);
1564		}
1565	}
1566
1567	if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1568		fprintf(stderr, "Dump terminated\n");
1569		exit(1);
1570	}
1571
1572	exit(0);
1573}
1574
1575
1576static int iproute_get(int argc, char **argv)
1577{
1578	struct {
1579		struct nlmsghdr	n;
1580		struct rtmsg		r;
1581		char  			buf[1024];
1582	} req;
1583	char  *idev = NULL;
1584	char  *odev = NULL;
1585	int connected = 0;
1586	int from_ok = 0;
1587	unsigned int mark = 0;
1588
1589	memset(&req, 0, sizeof(req));
1590
1591	iproute_reset_filter(0);
1592	filter.cloned = 2;
1593
1594	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1595	req.n.nlmsg_flags = NLM_F_REQUEST;
1596	req.n.nlmsg_type = RTM_GETROUTE;
1597	req.r.rtm_family = preferred_family;
1598	req.r.rtm_table = 0;
1599	req.r.rtm_protocol = 0;
1600	req.r.rtm_scope = 0;
1601	req.r.rtm_type = 0;
1602	req.r.rtm_src_len = 0;
1603	req.r.rtm_dst_len = 0;
1604	req.r.rtm_tos = 0;
1605
1606	while (argc > 0) {
1607		if (strcmp(*argv, "tos") == 0 ||
1608		    matches(*argv, "dsfield") == 0) {
1609			__u32 tos;
1610			NEXT_ARG();
1611			if (rtnl_dsfield_a2n(&tos, *argv))
1612				invarg("TOS value is invalid\n", *argv);
1613			req.r.rtm_tos = tos;
1614		} else if (matches(*argv, "from") == 0) {
1615			inet_prefix addr;
1616			NEXT_ARG();
1617			if (matches(*argv, "help") == 0)
1618				usage();
1619			from_ok = 1;
1620			get_prefix(&addr, *argv, req.r.rtm_family);
1621			if (req.r.rtm_family == AF_UNSPEC)
1622				req.r.rtm_family = addr.family;
1623			if (addr.bytelen)
1624				addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
1625			req.r.rtm_src_len = addr.bitlen;
1626		} else if (matches(*argv, "iif") == 0) {
1627			NEXT_ARG();
1628			idev = *argv;
1629		} else if (matches(*argv, "mark") == 0) {
1630			NEXT_ARG();
1631			get_unsigned(&mark, *argv, 0);
1632		} else if (matches(*argv, "oif") == 0 ||
1633			   strcmp(*argv, "dev") == 0) {
1634			NEXT_ARG();
1635			odev = *argv;
1636		} else if (matches(*argv, "uid") == 0) {
1637		        uid_t uid;
1638			NEXT_ARG();
1639			get_unsigned(&uid, *argv, 0);
1640			addattr32(&req.n, sizeof(req), RTA_UID, uid);
1641		} else if (matches(*argv, "notify") == 0) {
1642			req.r.rtm_flags |= RTM_F_NOTIFY;
1643		} else if (matches(*argv, "connected") == 0) {
1644			connected = 1;
1645		} else {
1646			inet_prefix addr;
1647			if (strcmp(*argv, "to") == 0) {
1648				NEXT_ARG();
1649			}
1650			if (matches(*argv, "help") == 0)
1651				usage();
1652			get_prefix(&addr, *argv, req.r.rtm_family);
1653			if (req.r.rtm_family == AF_UNSPEC)
1654				req.r.rtm_family = addr.family;
1655			if (addr.bytelen)
1656				addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
1657			req.r.rtm_dst_len = addr.bitlen;
1658		}
1659		argc--; argv++;
1660	}
1661
1662	if (req.r.rtm_dst_len == 0) {
1663		fprintf(stderr, "need at least a destination address\n");
1664		exit(1);
1665	}
1666
1667	if (idev || odev)  {
1668		int idx;
1669
1670		if (idev) {
1671			if ((idx = ll_name_to_index(idev)) == 0) {
1672				fprintf(stderr, "Cannot find device \"%s\"\n", idev);
1673				return -1;
1674			}
1675			addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1676		}
1677		if (odev) {
1678			if ((idx = ll_name_to_index(odev)) == 0) {
1679				fprintf(stderr, "Cannot find device \"%s\"\n", odev);
1680				return -1;
1681			}
1682			addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1683		}
1684	}
1685	if (mark)
1686		addattr32(&req.n, sizeof(req), RTA_MARK, mark);
1687
1688	if (req.r.rtm_family == AF_UNSPEC)
1689		req.r.rtm_family = AF_INET;
1690
1691	req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
1692
1693	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
1694		return -2;
1695
1696	if (connected && !from_ok) {
1697		struct rtmsg *r = NLMSG_DATA(&req.n);
1698		int len = req.n.nlmsg_len;
1699		struct rtattr * tb[RTA_MAX+1];
1700
1701		if (print_route(NULL, &req.n, (void*)stdout) < 0) {
1702			fprintf(stderr, "An error :-)\n");
1703			exit(1);
1704		}
1705
1706		if (req.n.nlmsg_type != RTM_NEWROUTE) {
1707			fprintf(stderr, "Not a route?\n");
1708			return -1;
1709		}
1710		len -= NLMSG_LENGTH(sizeof(*r));
1711		if (len < 0) {
1712			fprintf(stderr, "Wrong len %d\n", len);
1713			return -1;
1714		}
1715
1716		parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1717
1718		if (tb[RTA_PREFSRC]) {
1719			tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1720			r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1721		} else if (!tb[RTA_SRC]) {
1722			fprintf(stderr, "Failed to connect the route\n");
1723			return -1;
1724		}
1725		if (!odev && tb[RTA_OIF])
1726			tb[RTA_OIF]->rta_type = 0;
1727		if (tb[RTA_GATEWAY])
1728			tb[RTA_GATEWAY]->rta_type = 0;
1729		if (tb[RTA_VIA])
1730			tb[RTA_VIA]->rta_type = 0;
1731		if (!idev && tb[RTA_IIF])
1732			tb[RTA_IIF]->rta_type = 0;
1733		req.n.nlmsg_flags = NLM_F_REQUEST;
1734		req.n.nlmsg_type = RTM_GETROUTE;
1735
1736		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
1737			return -2;
1738	}
1739
1740	if (print_route(NULL, &req.n, (void*)stdout) < 0) {
1741		fprintf(stderr, "An error :-)\n");
1742		return -1;
1743	}
1744
1745	return 0;
1746}
1747
1748static int restore_handler(const struct sockaddr_nl *nl,
1749			   struct rtnl_ctrl_data *ctrl,
1750			   struct nlmsghdr *n, void *arg)
1751{
1752	int ret;
1753
1754	n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
1755
1756	ll_init_map(&rth);
1757
1758	ret = rtnl_talk(&rth, n, n, sizeof(*n));
1759	if ((ret < 0) && (errno == EEXIST))
1760		ret = 0;
1761
1762	return ret;
1763}
1764
1765static int route_dump_check_magic(void)
1766{
1767	int ret;
1768	__u32 magic = 0;
1769
1770	if (isatty(STDIN_FILENO)) {
1771		fprintf(stderr, "Can't restore route dump from a terminal\n");
1772		return -1;
1773	}
1774
1775	ret = fread(&magic, sizeof(magic), 1, stdin);
1776	if (magic != route_dump_magic) {
1777		fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic);
1778		return -1;
1779	}
1780
1781	return 0;
1782}
1783
1784static int iproute_restore(void)
1785{
1786	if (route_dump_check_magic())
1787		exit(-1);
1788
1789	exit(rtnl_from_file(stdin, &restore_handler, NULL));
1790}
1791
1792static int show_handler(const struct sockaddr_nl *nl,
1793			struct rtnl_ctrl_data *ctrl,
1794			struct nlmsghdr *n, void *arg)
1795{
1796	print_route(nl, n, stdout);
1797	return 0;
1798}
1799
1800static int iproute_showdump(void)
1801{
1802	if (route_dump_check_magic())
1803		exit(-1);
1804
1805	exit(rtnl_from_file(stdin, &show_handler, NULL));
1806}
1807
1808void iproute_reset_filter(int ifindex)
1809{
1810	memset(&filter, 0, sizeof(filter));
1811	filter.mdst.bitlen = -1;
1812	filter.msrc.bitlen = -1;
1813	filter.oif = ifindex;
1814	if (filter.oif > 0)
1815		filter.oifmask = -1;
1816}
1817
1818int do_iproute(int argc, char **argv)
1819{
1820	if (argc < 1)
1821		return iproute_list_flush_or_save(0, NULL, IPROUTE_LIST);
1822
1823	if (matches(*argv, "add") == 0)
1824		return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
1825				      argc-1, argv+1);
1826	if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
1827		return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
1828				      argc-1, argv+1);
1829	if (matches(*argv, "replace") == 0)
1830		return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
1831				      argc-1, argv+1);
1832	if (matches(*argv, "prepend") == 0)
1833		return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
1834				      argc-1, argv+1);
1835	if (matches(*argv, "append") == 0)
1836		return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
1837				      argc-1, argv+1);
1838	if (matches(*argv, "test") == 0)
1839		return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
1840				      argc-1, argv+1);
1841	if (matches(*argv, "delete") == 0)
1842		return iproute_modify(RTM_DELROUTE, 0,
1843				      argc-1, argv+1);
1844	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1845	    || matches(*argv, "lst") == 0)
1846		return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_LIST);
1847	if (matches(*argv, "get") == 0)
1848		return iproute_get(argc-1, argv+1);
1849	if (matches(*argv, "flush") == 0)
1850		return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_FLUSH);
1851	if (matches(*argv, "save") == 0)
1852		return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_SAVE);
1853	if (matches(*argv, "restore") == 0)
1854		return iproute_restore();
1855	if (matches(*argv, "showdump") == 0)
1856		return iproute_showdump();
1857	if (matches(*argv, "help") == 0)
1858		usage();
1859	fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
1860	exit(-1);
1861}
1862