| @@ -1,1813 +1,1816 @@ | | | @@ -1,1813 +1,1816 @@ |
1 | /* $NetBSD: route.c,v 1.155.4.3 2018/04/09 13:34:11 bouyer Exp $ */ | | 1 | /* $NetBSD: route.c,v 1.155.4.4 2018/08/25 07:06:48 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1983, 1989, 1991, 1993 | | 4 | * Copyright (c) 1983, 1989, 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the University nor the names of its contributors | | 15 | * 3. Neither the name of the University nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software | | 16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. | | 17 | * without specific prior written permission. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #ifndef lint | | 33 | #ifndef lint |
34 | __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\ | | 34 | __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\ |
35 | The Regents of the University of California. All rights reserved."); | | 35 | The Regents of the University of California. All rights reserved."); |
36 | #endif /* not lint */ | | 36 | #endif /* not lint */ |
37 | | | 37 | |
38 | #ifndef lint | | 38 | #ifndef lint |
39 | #if 0 | | 39 | #if 0 |
40 | static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; | | 40 | static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; |
41 | #else | | 41 | #else |
42 | __RCSID("$NetBSD: route.c,v 1.155.4.3 2018/04/09 13:34:11 bouyer Exp $"); | | 42 | __RCSID("$NetBSD: route.c,v 1.155.4.4 2018/08/25 07:06:48 martin Exp $"); |
43 | #endif | | 43 | #endif |
44 | #endif /* not lint */ | | 44 | #endif /* not lint */ |
45 | | | 45 | |
46 | #include <sys/param.h> | | 46 | #include <sys/param.h> |
47 | #include <sys/file.h> | | 47 | #include <sys/file.h> |
48 | #include <sys/socket.h> | | 48 | #include <sys/socket.h> |
49 | #include <sys/ioctl.h> | | 49 | #include <sys/ioctl.h> |
50 | #include <sys/sysctl.h> | | 50 | #include <sys/sysctl.h> |
51 | | | 51 | |
52 | #include <net/if.h> | | 52 | #include <net/if.h> |
53 | #include <net/route.h> | | 53 | #include <net/route.h> |
54 | #include <net/if_dl.h> | | 54 | #include <net/if_dl.h> |
55 | #include <net80211/ieee80211_netbsd.h> | | 55 | #include <net80211/ieee80211_netbsd.h> |
56 | #include <netinet/in.h> | | 56 | #include <netinet/in.h> |
57 | #include <netatalk/at.h> | | 57 | #include <netatalk/at.h> |
58 | #include <netmpls/mpls.h> | | 58 | #include <netmpls/mpls.h> |
59 | #include <arpa/inet.h> | | 59 | #include <arpa/inet.h> |
60 | #include <netdb.h> | | 60 | #include <netdb.h> |
61 | | | 61 | |
62 | #include <errno.h> | | 62 | #include <errno.h> |
63 | #include <unistd.h> | | 63 | #include <unistd.h> |
64 | #include <stdio.h> | | 64 | #include <stdio.h> |
65 | #include <ctype.h> | | 65 | #include <ctype.h> |
66 | #include <stdlib.h> | | 66 | #include <stdlib.h> |
67 | #include <string.h> | | 67 | #include <string.h> |
68 | #include <time.h> | | 68 | #include <time.h> |
69 | #include <paths.h> | | 69 | #include <paths.h> |
70 | #include <err.h> | | 70 | #include <err.h> |
71 | | | 71 | |
72 | #include "keywords.h" | | 72 | #include "keywords.h" |
73 | #include "extern.h" | | 73 | #include "extern.h" |
74 | #include "prog_ops.h" | | 74 | #include "prog_ops.h" |
75 | #include "rtutil.h" | | 75 | #include "rtutil.h" |
76 | | | 76 | |
77 | union sockunion { | | 77 | union sockunion { |
78 | struct sockaddr sa; | | 78 | struct sockaddr sa; |
79 | struct sockaddr_in sin; | | 79 | struct sockaddr_in sin; |
80 | #ifdef INET6 | | 80 | #ifdef INET6 |
81 | struct sockaddr_in6 sin6; | | 81 | struct sockaddr_in6 sin6; |
82 | #endif | | 82 | #endif |
83 | struct sockaddr_at sat; | | 83 | struct sockaddr_at sat; |
84 | struct sockaddr_dl sdl; | | 84 | struct sockaddr_dl sdl; |
85 | #ifndef SMALL | | 85 | #ifndef SMALL |
86 | struct sockaddr_mpls smpls; | | 86 | struct sockaddr_mpls smpls; |
87 | #endif /* SMALL */ | | 87 | #endif /* SMALL */ |
88 | struct sockaddr_storage sstorage; | | 88 | struct sockaddr_storage sstorage; |
89 | }; | | 89 | }; |
90 | | | 90 | |
91 | typedef union sockunion *sup; | | 91 | typedef union sockunion *sup; |
92 | | | 92 | |
93 | struct sou { | | 93 | struct sou { |
94 | union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa, | | 94 | union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa, |
95 | *so_ifp, *so_mpls; | | 95 | *so_ifp, *so_mpls; |
96 | }; | | 96 | }; |
97 | | | 97 | |
98 | static const char *route_strerror(int); | | 98 | static const char *route_strerror(int); |
99 | static void set_metric(const char *, int); | | 99 | static void set_metric(const char *, int); |
100 | static int newroute(int, char *const *); | | 100 | static int newroute(int, char *const *); |
101 | static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *); | | 101 | static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *); |
102 | #ifdef INET6 | | 102 | #ifdef INET6 |
103 | static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *); | | 103 | static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *); |
104 | #endif | | 104 | #endif |
105 | static int getaddr(int, const char *, struct hostent **, struct sou *); | | 105 | static int getaddr(int, const char *, struct hostent **, struct sou *); |
106 | static int flushroutes(int, char *const [], int); | | 106 | static int flushroutes(int, char *const [], int); |
107 | static char *netmask_string(const struct sockaddr *, int, int); | | 107 | static char *netmask_string(const struct sockaddr *, int, int); |
108 | static int prefixlen(const char *, struct sou *); | | 108 | static int prefixlen(const char *, struct sou *); |
109 | #ifndef SMALL | | 109 | #ifndef SMALL |
110 | static void interfaces(void); | | 110 | static void interfaces(void); |
111 | static void monitor(int, char * const *); | | 111 | static void monitor(int, char * const *); |
112 | static int print_getmsg(struct rt_msghdr *, int, struct sou *); | | 112 | static int print_getmsg(struct rt_msghdr *, int, struct sou *); |
113 | static const char *linkstate(struct if_msghdr *); | | 113 | static const char *linkstate(struct if_msghdr *); |
114 | static sup readtag(sup, const char *); | | 114 | static sup readtag(sup, const char *); |
115 | static void addtag(sup, const char *, int); | | 115 | static void addtag(sup, const char *, int); |
116 | #endif /* SMALL */ | | 116 | #endif /* SMALL */ |
117 | static int rtmsg(int, int, struct sou *); | | 117 | static int rtmsg(int, int, struct sou *); |
118 | static void mask_addr(struct sou *); | | 118 | static void mask_addr(struct sou *); |
119 | static void print_rtmsg(struct rt_msghdr *, int); | | 119 | static void print_rtmsg(struct rt_msghdr *, int); |
120 | static void pmsg_common(struct rt_msghdr *); | | 120 | static void pmsg_common(struct rt_msghdr *); |
121 | static void pmsg_addrs(const char *, int); | | 121 | static void pmsg_addrs(const char *, int); |
122 | static void bprintf(FILE *, int, const char *); | | 122 | static void bprintf(FILE *, int, const char *); |
123 | static void sodump(sup, const char *); | | 123 | static void sodump(sup, const char *); |
124 | static void sockaddr(const char *, struct sockaddr *); | | 124 | static void sockaddr(const char *, struct sockaddr *); |
125 | | | 125 | |
126 | int pid, rtm_addrs; | | 126 | int pid, rtm_addrs; |
127 | int sock; | | 127 | int sock; |
128 | int forcehost, forcenet, doflush, af; | | 128 | int forcehost, forcenet, doflush, af; |
129 | int iflag, Lflag, nflag, qflag, tflag, Sflag, Tflag; | | 129 | int iflag, Lflag, nflag, qflag, tflag, Sflag, Tflag; |
130 | int verbose, aflen = sizeof(struct sockaddr_in), rtag; | | 130 | int verbose, aflen = sizeof(struct sockaddr_in), rtag; |
131 | int locking, lockrest, debugonly, shortoutput; | | 131 | int locking, lockrest, debugonly, shortoutput; |
132 | struct rt_metrics rt_metrics; | | 132 | struct rt_metrics rt_metrics; |
133 | int rtm_inits; | | 133 | int rtm_inits; |
134 | short ns_nullh[] = {0,0,0}; | | 134 | short ns_nullh[] = {0,0,0}; |
135 | short ns_bh[] = {-1,-1,-1}; | | 135 | short ns_bh[] = {-1,-1,-1}; |
136 | | | 136 | |
137 | static const char opts[] = "dfLnqSsTtv"; | | 137 | static const char opts[] = "dfLnqSsTtv"; |
138 | | | 138 | |
139 | void | | 139 | void |
140 | usage(const char *cp) | | 140 | usage(const char *cp) |
141 | { | | 141 | { |
142 | | | 142 | |
143 | if (cp) | | 143 | if (cp) |
144 | warnx("botched keyword: %s", cp); | | 144 | warnx("botched keyword: %s", cp); |
145 | (void)fprintf(stderr, | | 145 | (void)fprintf(stderr, |
146 | "Usage: %s [-%s] cmd [[-<qualifers>] args]\n", getprogname(), opts); | | 146 | "Usage: %s [-%s] cmd [[-<qualifers>] args]\n", getprogname(), opts); |
147 | exit(1); | | 147 | exit(1); |
148 | /* NOTREACHED */ | | 148 | /* NOTREACHED */ |
149 | } | | 149 | } |
150 | | | 150 | |
151 | #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x" | | 151 | #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x" |
152 | #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \ | | 152 | #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \ |
153 | (__enaddr)[3], (__enaddr)[4], (__enaddr)[5] | | 153 | (__enaddr)[3], (__enaddr)[4], (__enaddr)[5] |
154 | | | 154 | |
155 | int | | 155 | int |
156 | main(int argc, char * const *argv) | | 156 | main(int argc, char * const *argv) |
157 | { | | 157 | { |
158 | int ch; | | 158 | int ch; |
159 | | | 159 | |
160 | if (argc < 2) | | 160 | if (argc < 2) |
161 | usage(NULL); | | 161 | usage(NULL); |
162 | | | 162 | |
163 | while ((ch = getopt(argc, argv, opts)) != -1) | | 163 | while ((ch = getopt(argc, argv, opts)) != -1) |
164 | switch (ch) { | | 164 | switch (ch) { |
165 | case 'd': | | 165 | case 'd': |
166 | debugonly = 1; | | 166 | debugonly = 1; |
167 | break; | | 167 | break; |
168 | case 'f': | | 168 | case 'f': |
169 | doflush = 1; | | 169 | doflush = 1; |
170 | break; | | 170 | break; |
171 | case 'L': | | 171 | case 'L': |
172 | Lflag = RT_LFLAG; | | 172 | Lflag = RT_LFLAG; |
173 | break; | | 173 | break; |
174 | case 'n': | | 174 | case 'n': |
175 | nflag = RT_NFLAG; | | 175 | nflag = RT_NFLAG; |
176 | break; | | 176 | break; |
177 | case 'q': | | 177 | case 'q': |
178 | qflag = 1; | | 178 | qflag = 1; |
179 | break; | | 179 | break; |
180 | case 'S': | | 180 | case 'S': |
181 | Sflag = 1; | | 181 | Sflag = 1; |
182 | break; | | 182 | break; |
183 | case 's': | | 183 | case 's': |
184 | shortoutput = 1; | | 184 | shortoutput = 1; |
185 | break; | | 185 | break; |
186 | case 'T': | | 186 | case 'T': |
187 | Tflag = RT_TFLAG; | | 187 | Tflag = RT_TFLAG; |
188 | break; | | 188 | break; |
189 | case 't': | | 189 | case 't': |
190 | tflag = 1; | | 190 | tflag = 1; |
191 | break; | | 191 | break; |
192 | case 'v': | | 192 | case 'v': |
193 | verbose = RT_VFLAG; | | 193 | verbose = RT_VFLAG; |
194 | break; | | 194 | break; |
195 | case '?': | | 195 | case '?': |
196 | default: | | 196 | default: |
197 | usage(NULL); | | 197 | usage(NULL); |
198 | /*NOTREACHED*/ | | 198 | /*NOTREACHED*/ |
199 | } | | 199 | } |
200 | argc -= optind; | | 200 | argc -= optind; |
201 | argv += optind; | | 201 | argv += optind; |
202 | | | 202 | |
203 | if (prog_init && prog_init() == -1) | | 203 | if (prog_init && prog_init() == -1) |
204 | err(1, "init failed"); | | 204 | err(1, "init failed"); |
205 | | | 205 | |
206 | pid = prog_getpid(); | | 206 | pid = prog_getpid(); |
207 | if (tflag) | | 207 | if (tflag) |
208 | sock = prog_open("/dev/null", O_WRONLY, 0); | | 208 | sock = prog_open("/dev/null", O_WRONLY, 0); |
209 | else | | 209 | else |
210 | sock = prog_socket(PF_ROUTE, SOCK_RAW, 0); | | 210 | sock = prog_socket(PF_ROUTE, SOCK_RAW, 0); |
211 | if (sock < 0) | | 211 | if (sock < 0) |
212 | err(EXIT_FAILURE, "socket"); | | 212 | err(EXIT_FAILURE, "socket"); |
213 | | | 213 | |
214 | if (*argv == NULL) { | | 214 | if (*argv == NULL) { |
215 | if (doflush) | | 215 | if (doflush) |
216 | ch = K_FLUSH; | | 216 | ch = K_FLUSH; |
217 | else | | 217 | else |
218 | goto no_cmd; | | 218 | goto no_cmd; |
219 | } else | | 219 | } else |
220 | ch = keyword(*argv); | | 220 | ch = keyword(*argv); |
221 | | | 221 | |
222 | switch (ch) { | | 222 | switch (ch) { |
223 | #ifndef SMALL | | 223 | #ifndef SMALL |
224 | case K_GET: | | 224 | case K_GET: |
225 | #endif /* SMALL */ | | 225 | #endif /* SMALL */ |
226 | case K_CHANGE: | | 226 | case K_CHANGE: |
227 | case K_ADD: | | 227 | case K_ADD: |
228 | case K_DELETE: | | 228 | case K_DELETE: |
229 | if (doflush) | | 229 | if (doflush) |
230 | (void)flushroutes(1, argv, 0); | | 230 | (void)flushroutes(1, argv, 0); |
231 | return newroute(argc, argv); | | 231 | return newroute(argc, argv); |
232 | | | 232 | |
233 | case K_SHOW: | | 233 | case K_SHOW: |
234 | show(argc, argv, Lflag|nflag|Tflag|verbose); | | 234 | show(argc, argv, Lflag|nflag|Tflag|verbose); |
235 | return 0; | | 235 | return 0; |
236 | | | 236 | |
237 | #ifndef SMALL | | 237 | #ifndef SMALL |
238 | case K_MONITOR: | | 238 | case K_MONITOR: |
239 | monitor(argc, argv); | | 239 | monitor(argc, argv); |
240 | return 0; | | 240 | return 0; |
241 | | | 241 | |
242 | #endif /* SMALL */ | | 242 | #endif /* SMALL */ |
243 | case K_FLUSH: | | 243 | case K_FLUSH: |
244 | return flushroutes(argc, argv, 0); | | 244 | return flushroutes(argc, argv, 0); |
245 | | | 245 | |
246 | case K_FLUSHALL: | | 246 | case K_FLUSHALL: |
247 | return flushroutes(argc, argv, 1); | | 247 | return flushroutes(argc, argv, 1); |
248 | no_cmd: | | 248 | no_cmd: |
249 | default: | | 249 | default: |
250 | usage(*argv); | | 250 | usage(*argv); |
251 | /*NOTREACHED*/ | | 251 | /*NOTREACHED*/ |
252 | } | | 252 | } |
253 | } | | 253 | } |
254 | | | 254 | |
255 | static char * | | 255 | static char * |
256 | netmask_string(const struct sockaddr *mask, int len, int family) | | 256 | netmask_string(const struct sockaddr *mask, int len, int family) |
257 | { | | 257 | { |
258 | static char smask[INET6_ADDRSTRLEN]; | | 258 | static char smask[INET6_ADDRSTRLEN]; |
259 | struct sockaddr_in nsin; | | 259 | struct sockaddr_in nsin; |
260 | struct sockaddr_in6 nsin6; | | 260 | struct sockaddr_in6 nsin6; |
261 | | | 261 | |
262 | if (len >= 0) | | 262 | if (len >= 0) |
263 | snprintf(smask, sizeof(smask), "%d", len); | | 263 | snprintf(smask, sizeof(smask), "%d", len); |
264 | else { | | 264 | else { |
265 | switch (family) { | | 265 | switch (family) { |
266 | case AF_INET: | | 266 | case AF_INET: |
267 | memset(&nsin, 0, sizeof(nsin)); | | 267 | memset(&nsin, 0, sizeof(nsin)); |
268 | memcpy(&nsin, mask, mask->sa_len); | | 268 | memcpy(&nsin, mask, mask->sa_len); |
269 | snprintf(smask, sizeof(smask), "%s", | | 269 | snprintf(smask, sizeof(smask), "%s", |
270 | inet_ntoa(nsin.sin_addr)); | | 270 | inet_ntoa(nsin.sin_addr)); |
271 | break; | | 271 | break; |
272 | case AF_INET6: | | 272 | case AF_INET6: |
273 | memset(&nsin6, 0, sizeof(nsin6)); | | 273 | memset(&nsin6, 0, sizeof(nsin6)); |
274 | memcpy(&nsin6, mask, mask->sa_len); | | 274 | memcpy(&nsin6, mask, mask->sa_len); |
275 | inet_ntop(family, &nsin6.sin6_addr, smask, | | 275 | inet_ntop(family, &nsin6.sin6_addr, smask, |
276 | sizeof(smask)); | | 276 | sizeof(smask)); |
277 | break; | | 277 | break; |
278 | default: | | 278 | default: |
279 | snprintf(smask, sizeof(smask), "%s", any_ntoa(mask)); | | 279 | snprintf(smask, sizeof(smask), "%s", any_ntoa(mask)); |
280 | } | | 280 | } |
281 | } | | 281 | } |
282 | | | 282 | |
283 | return smask; | | 283 | return smask; |
284 | } | | 284 | } |
285 | /* | | 285 | /* |
286 | * Purge all entries in the routing tables not | | 286 | * Purge all entries in the routing tables not |
287 | * associated with network interfaces. | | 287 | * associated with network interfaces. |
288 | */ | | 288 | */ |
289 | static int | | 289 | static int |
290 | flushroutes(int argc, char * const argv[], int doall) | | 290 | flushroutes(int argc, char * const argv[], int doall) |
291 | { | | 291 | { |
292 | struct sockaddr *sa; | | 292 | struct sockaddr *sa; |
293 | size_t needed; | | 293 | size_t needed; |
294 | int flags, mib[6], rlen, seqno; | | 294 | int flags, mib[6], rlen, seqno; |
295 | char *buf, *next, *lim; | | 295 | char *buf, *next, *lim; |
296 | const char *afname; | | 296 | const char *afname; |
297 | struct rt_msghdr *rtm; | | 297 | struct rt_msghdr *rtm; |
298 | | | 298 | |
299 | flags = 0; | | 299 | flags = 0; |
300 | af = AF_UNSPEC; | | 300 | af = AF_UNSPEC; |
301 | /* Don't want to read back our messages */ | | 301 | /* Don't want to read back our messages */ |
302 | prog_shutdown(sock, SHUT_RD); | | 302 | prog_shutdown(sock, SHUT_RD); |
303 | parse_show_opts(argc, argv, &af, &flags, &afname, false); | | 303 | parse_show_opts(argc, argv, &af, &flags, &afname, false); |
304 | mib[0] = CTL_NET; | | 304 | mib[0] = CTL_NET; |
305 | mib[1] = PF_ROUTE; | | 305 | mib[1] = PF_ROUTE; |
306 | mib[2] = 0; /* protocol */ | | 306 | mib[2] = 0; /* protocol */ |
307 | mib[3] = 0; /* wildcard address family */ | | 307 | mib[3] = 0; /* wildcard address family */ |
308 | mib[4] = NET_RT_DUMP; | | 308 | mib[4] = NET_RT_DUMP; |
309 | mib[5] = 0; /* no flags */ | | 309 | mib[5] = 0; /* no flags */ |
310 | if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | | 310 | if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) |
311 | err(EXIT_FAILURE, "route-sysctl-estimate"); | | 311 | err(EXIT_FAILURE, "route-sysctl-estimate"); |
312 | buf = lim = NULL; | | 312 | buf = lim = NULL; |
313 | if (needed) { | | 313 | if (needed) { |
314 | if ((buf = malloc(needed)) == NULL) | | 314 | if ((buf = malloc(needed)) == NULL) |
315 | err(EXIT_FAILURE, "malloc"); | | 315 | err(EXIT_FAILURE, "malloc"); |
316 | if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) | | 316 | if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) |
317 | err(EXIT_FAILURE, "actual retrieval of routing table"); | | 317 | err(EXIT_FAILURE, "actual retrieval of routing table"); |
318 | lim = buf + needed; | | 318 | lim = buf + needed; |
319 | } | | 319 | } |
320 | if (verbose) { | | 320 | if (verbose) { |
321 | (void)printf("Examining routing table from sysctl\n"); | | 321 | (void)printf("Examining routing table from sysctl\n"); |
322 | if (af != AF_UNSPEC) | | 322 | if (af != AF_UNSPEC) |
323 | printf("(address family %s)\n", afname); | | 323 | printf("(address family %s)\n", afname); |
324 | } | | 324 | } |
325 | if (needed == 0) | | 325 | if (needed == 0) |
326 | return 0; | | 326 | return 0; |
327 | seqno = 0; /* ??? */ | | 327 | seqno = 0; /* ??? */ |
328 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | | 328 | for (next = buf; next < lim; next += rtm->rtm_msglen) { |
329 | rtm = (struct rt_msghdr *)next; | | 329 | rtm = (struct rt_msghdr *)next; |
330 | sa = (struct sockaddr *)(rtm + 1); | | 330 | sa = (struct sockaddr *)(rtm + 1); |
331 | if (verbose) | | 331 | if (verbose) |
332 | print_rtmsg(rtm, rtm->rtm_msglen); | | 332 | print_rtmsg(rtm, rtm->rtm_msglen); |
333 | if ((rtm->rtm_flags & flags) != flags) | | 333 | if ((rtm->rtm_flags & flags) != flags) |
334 | continue; | | 334 | continue; |
335 | if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC)) && !doall) | | 335 | if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC)) && !doall) |
336 | continue; | | 336 | continue; |
337 | if (af != AF_UNSPEC && sa->sa_family != af) | | 337 | if (af != AF_UNSPEC && sa->sa_family != af) |
338 | continue; | | 338 | continue; |
339 | if (debugonly) | | 339 | if (debugonly) |
340 | continue; | | 340 | continue; |
341 | rtm->rtm_type = RTM_DELETE; | | 341 | rtm->rtm_type = RTM_DELETE; |
342 | rtm->rtm_seq = seqno; | | 342 | rtm->rtm_seq = seqno; |
343 | do { | | 343 | do { |
344 | rlen = prog_write(sock, next, rtm->rtm_msglen); | | 344 | rlen = prog_write(sock, next, rtm->rtm_msglen); |
345 | } while (rlen == -1 && errno == ENOBUFS); | | 345 | } while (rlen == -1 && errno == ENOBUFS); |
346 | if (rlen == -1) { | | 346 | if (rlen == -1) { |
347 | warnx("writing to routing socket: %s", | | 347 | warnx("writing to routing socket: %s", |
348 | route_strerror(errno)); | | 348 | route_strerror(errno)); |
349 | return 1; | | 349 | return 1; |
350 | } | | 350 | } |
351 | if (rlen < (int)rtm->rtm_msglen) { | | 351 | if (rlen < (int)rtm->rtm_msglen) { |
352 | warnx("write to routing socket, got %d for rlen", rlen); | | 352 | warnx("write to routing socket, got %d for rlen", rlen); |
353 | return 1; | | 353 | return 1; |
354 | } | | 354 | } |
355 | seqno++; | | 355 | seqno++; |
356 | if (qflag) | | 356 | if (qflag) |
357 | continue; | | 357 | continue; |
358 | if (verbose) | | 358 | if (verbose) |
359 | print_rtmsg(rtm, rlen); | | 359 | print_rtmsg(rtm, rlen); |
360 | else { | | 360 | else { |
361 | (void)printf("%-20.20s ", netname(sa, NULL, nflag)); | | 361 | (void)printf("%-20.20s ", netname(sa, NULL, nflag)); |
362 | sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) + | | 362 | sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) + |
363 | (char *)sa); | | 363 | (char *)sa); |
364 | (void)printf("%-20.20s ", routename(sa, nflag)); | | 364 | (void)printf("%-20.20s ", routename(sa, nflag)); |
365 | (void)printf("done\n"); | | 365 | (void)printf("done\n"); |
366 | } | | 366 | } |
367 | } | | 367 | } |
368 | free(buf); | | 368 | free(buf); |
369 | return 0; | | 369 | return 0; |
370 | } | | 370 | } |
371 | | | 371 | |
372 | static const char * | | 372 | static const char * |
373 | route_strerror(int error) | | 373 | route_strerror(int error) |
374 | { | | 374 | { |
375 | | | 375 | |
376 | switch (error) { | | 376 | switch (error) { |
377 | case ESRCH: | | 377 | case ESRCH: |
378 | return "not in table"; | | 378 | return "not in table"; |
379 | case EBUSY: | | 379 | case EBUSY: |
380 | return "entry in use"; | | 380 | return "entry in use"; |
381 | case ENOBUFS: | | 381 | case ENOBUFS: |
382 | return "routing table overflow"; | | 382 | return "routing table overflow"; |
383 | default: | | 383 | default: |
384 | return strerror(error); | | 384 | return strerror(error); |
385 | } | | 385 | } |
386 | } | | 386 | } |
387 | | | 387 | |
388 | static void | | 388 | static void |
389 | set_metric(const char *value, int key) | | 389 | set_metric(const char *value, int key) |
390 | { | | 390 | { |
391 | int flag = 0; | | 391 | int flag = 0; |
392 | uint64_t noval, *valp = &noval; | | 392 | uint64_t noval, *valp = &noval; |
393 | | | 393 | |
394 | switch (key) { | | 394 | switch (key) { |
395 | #define caseof(x, y, z) \ | | 395 | #define caseof(x, y, z) \ |
396 | case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break | | 396 | case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break |
397 | caseof(K_MTU, RTV_MTU, rmx_mtu); | | 397 | caseof(K_MTU, RTV_MTU, rmx_mtu); |
398 | caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); | | 398 | caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); |
399 | caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); | | 399 | caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); |
400 | caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); | | 400 | caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); |
401 | caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); | | 401 | caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); |
402 | caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); | | 402 | caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); |
403 | caseof(K_RTT, RTV_RTT, rmx_rtt); | | 403 | caseof(K_RTT, RTV_RTT, rmx_rtt); |
404 | caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); | | 404 | caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); |
405 | } | | 405 | } |
406 | rtm_inits |= flag; | | 406 | rtm_inits |= flag; |
407 | if (lockrest || locking) | | 407 | if (lockrest || locking) |
408 | rt_metrics.rmx_locks |= flag; | | 408 | rt_metrics.rmx_locks |= flag; |
409 | if (locking) | | 409 | if (locking) |
410 | locking = 0; | | 410 | locking = 0; |
411 | *valp = strtoul(value, NULL, 0); | | 411 | *valp = strtoul(value, NULL, 0); |
412 | } | | 412 | } |
413 | | | 413 | |
414 | static int | | 414 | static int |
415 | newroute(int argc, char *const *argv) | | 415 | newroute(int argc, char *const *argv) |
416 | { | | 416 | { |
417 | const char *cmd, *dest = "", *gateway = ""; | | 417 | const char *cmd, *dest = "", *gateway = ""; |
418 | int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; | | 418 | int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; |
419 | int key; | | 419 | int key; |
420 | struct hostent *hp = 0; | | 420 | struct hostent *hp = 0; |
421 | struct sou sou, *soup = &sou; | | 421 | struct sou sou, *soup = &sou; |
422 | | | 422 | |
423 | sou.so_dst = calloc(1, sizeof(union sockunion)); | | 423 | sou.so_dst = calloc(1, sizeof(union sockunion)); |
424 | sou.so_gate = calloc(1, sizeof(union sockunion)); | | 424 | sou.so_gate = calloc(1, sizeof(union sockunion)); |
425 | sou.so_mask = calloc(1, sizeof(union sockunion)); | | 425 | sou.so_mask = calloc(1, sizeof(union sockunion)); |
426 | sou.so_genmask = calloc(1, sizeof(union sockunion)); | | 426 | sou.so_genmask = calloc(1, sizeof(union sockunion)); |
427 | sou.so_ifa = calloc(1, sizeof(union sockunion)); | | 427 | sou.so_ifa = calloc(1, sizeof(union sockunion)); |
428 | sou.so_ifp = calloc(1, sizeof(union sockunion)); | | 428 | sou.so_ifp = calloc(1, sizeof(union sockunion)); |
429 | sou.so_mpls = calloc(1, sizeof(union sockunion)); | | 429 | sou.so_mpls = calloc(1, sizeof(union sockunion)); |
430 | | | 430 | |
431 | if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL || | | 431 | if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL || |
432 | sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL || | | 432 | sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL || |
433 | sou.so_mpls == NULL) | | 433 | sou.so_mpls == NULL) |
434 | errx(EXIT_FAILURE, "Cannot allocate memory"); | | 434 | errx(EXIT_FAILURE, "Cannot allocate memory"); |
435 | | | 435 | |
436 | cmd = argv[0]; | | 436 | cmd = argv[0]; |
437 | af = AF_UNSPEC; | | 437 | af = AF_UNSPEC; |
438 | if (*cmd != 'g') { | | 438 | if (*cmd != 'g') { |
439 | /* Don't want to read back our messages */ | | 439 | /* Don't want to read back our messages */ |
440 | prog_shutdown(sock, SHUT_RD); | | 440 | prog_shutdown(sock, SHUT_RD); |
441 | } | | 441 | } |
442 | while (--argc > 0) { | | 442 | while (--argc > 0) { |
443 | if (**(++argv)== '-') { | | 443 | if (**(++argv)== '-') { |
444 | switch (key = keyword(1 + *argv)) { | | 444 | switch (key = keyword(1 + *argv)) { |
445 | | | 445 | |
446 | case K_SA: | | 446 | case K_SA: |
447 | af = PF_ROUTE; | | 447 | af = PF_ROUTE; |
448 | aflen = sizeof(union sockunion); | | 448 | aflen = sizeof(union sockunion); |
449 | break; | | 449 | break; |
450 | | | 450 | |
451 | #ifndef SMALL | | 451 | #ifndef SMALL |
452 | case K_ATALK: | | 452 | case K_ATALK: |
453 | af = AF_APPLETALK; | | 453 | af = AF_APPLETALK; |
454 | aflen = sizeof(struct sockaddr_at); | | 454 | aflen = sizeof(struct sockaddr_at); |
455 | break; | | 455 | break; |
456 | #endif | | 456 | #endif |
457 | | | 457 | |
458 | case K_INET: | | 458 | case K_INET: |
459 | af = AF_INET; | | 459 | af = AF_INET; |
460 | aflen = sizeof(struct sockaddr_in); | | 460 | aflen = sizeof(struct sockaddr_in); |
461 | break; | | 461 | break; |
462 | | | 462 | |
463 | #ifdef INET6 | | 463 | #ifdef INET6 |
464 | case K_INET6: | | 464 | case K_INET6: |
465 | af = AF_INET6; | | 465 | af = AF_INET6; |
466 | aflen = sizeof(struct sockaddr_in6); | | 466 | aflen = sizeof(struct sockaddr_in6); |
467 | break; | | 467 | break; |
468 | #endif | | 468 | #endif |
469 | | | 469 | |
470 | case K_LINK: | | 470 | case K_LINK: |
471 | af = AF_LINK; | | 471 | af = AF_LINK; |
472 | aflen = sizeof(struct sockaddr_dl); | | 472 | aflen = sizeof(struct sockaddr_dl); |
473 | break; | | 473 | break; |
474 | | | 474 | |
475 | #ifndef SMALL | | 475 | #ifndef SMALL |
476 | case K_MPLS: | | 476 | case K_MPLS: |
477 | af = AF_MPLS; | | 477 | af = AF_MPLS; |
478 | aflen = sizeof(struct sockaddr_mpls); | | 478 | aflen = sizeof(struct sockaddr_mpls); |
479 | break; | | 479 | break; |
480 | case K_TAG: | | 480 | case K_TAG: |
481 | if (!--argc) | | 481 | if (!--argc) |
482 | usage(1+*argv); | | 482 | usage(1+*argv); |
483 | af = AF_MPLS; | | 483 | af = AF_MPLS; |
484 | aflen = sizeof(struct sockaddr_mpls); | | 484 | aflen = sizeof(struct sockaddr_mpls); |
485 | (void)getaddr(RTA_TAG, *++argv, 0, soup); | | 485 | (void)getaddr(RTA_TAG, *++argv, 0, soup); |
486 | break; | | 486 | break; |
487 | #endif /* SMALL */ | | 487 | #endif /* SMALL */ |
488 | | | 488 | |
489 | case K_IFACE: | | 489 | case K_IFACE: |
490 | case K_INTERFACE: | | 490 | case K_INTERFACE: |
491 | iflag++; | | 491 | iflag++; |
492 | break; | | 492 | break; |
493 | case K_NOSTATIC: | | 493 | case K_NOSTATIC: |
494 | flags &= ~RTF_STATIC; | | 494 | flags &= ~RTF_STATIC; |
495 | break; | | 495 | break; |
496 | case K_LOCK: | | 496 | case K_LOCK: |
497 | locking = 1; | | 497 | locking = 1; |
498 | break; | | 498 | break; |
499 | case K_LOCKREST: | | 499 | case K_LOCKREST: |
500 | lockrest = 1; | | 500 | lockrest = 1; |
501 | break; | | 501 | break; |
502 | case K_HOST: | | 502 | case K_HOST: |
503 | forcehost++; | | 503 | forcehost++; |
504 | break; | | 504 | break; |
505 | case K_REJECT: | | 505 | case K_REJECT: |
506 | flags |= RTF_REJECT; | | 506 | flags |= RTF_REJECT; |
507 | break; | | 507 | break; |
508 | case K_NOREJECT: | | 508 | case K_NOREJECT: |
509 | flags &= ~RTF_REJECT; | | 509 | flags &= ~RTF_REJECT; |
510 | break; | | 510 | break; |
511 | case K_BLACKHOLE: | | 511 | case K_BLACKHOLE: |
512 | flags |= RTF_BLACKHOLE; | | 512 | flags |= RTF_BLACKHOLE; |
513 | break; | | 513 | break; |
514 | case K_NOBLACKHOLE: | | 514 | case K_NOBLACKHOLE: |
515 | flags &= ~RTF_BLACKHOLE; | | 515 | flags &= ~RTF_BLACKHOLE; |
516 | break; | | 516 | break; |
517 | case K_PROTO1: | | 517 | case K_PROTO1: |
518 | flags |= RTF_PROTO1; | | 518 | flags |= RTF_PROTO1; |
519 | break; | | 519 | break; |
520 | case K_PROTO2: | | 520 | case K_PROTO2: |
521 | flags |= RTF_PROTO2; | | 521 | flags |= RTF_PROTO2; |
522 | break; | | 522 | break; |
523 | case K_PROXY: | | 523 | case K_PROXY: |
524 | flags |= RTF_ANNOUNCE; | | 524 | flags |= RTF_ANNOUNCE; |
525 | break; | | 525 | break; |
526 | case K_CONNECTED: | | 526 | case K_CONNECTED: |
527 | flags |= RTF_CONNECTED; | | 527 | flags |= RTF_CONNECTED; |
528 | break; | | 528 | break; |
529 | case K_NOCONNECTED: | | 529 | case K_NOCONNECTED: |
530 | flags &= ~RTF_CONNECTED; | | 530 | flags &= ~RTF_CONNECTED; |
531 | break; | | 531 | break; |
532 | case K_STATIC: | | 532 | case K_STATIC: |
533 | flags |= RTF_STATIC; | | 533 | flags |= RTF_STATIC; |
534 | break; | | 534 | break; |
535 | case K_IFA: | | 535 | case K_IFA: |
536 | if (!--argc) | | 536 | if (!--argc) |
537 | usage(1+*argv); | | 537 | usage(1+*argv); |
538 | (void)getaddr(RTA_IFA, *++argv, 0, soup); | | 538 | (void)getaddr(RTA_IFA, *++argv, 0, soup); |
539 | break; | | 539 | break; |
540 | case K_IFP: | | 540 | case K_IFP: |
541 | if (!--argc) | | 541 | if (!--argc) |
542 | usage(1+*argv); | | 542 | usage(1+*argv); |
543 | (void)getaddr(RTA_IFP, *++argv, 0, soup); | | 543 | (void)getaddr(RTA_IFP, *++argv, 0, soup); |
544 | break; | | 544 | break; |
545 | case K_GENMASK: | | 545 | case K_GENMASK: |
546 | if (!--argc) | | 546 | if (!--argc) |
547 | usage(1+*argv); | | 547 | usage(1+*argv); |
548 | (void)getaddr(RTA_GENMASK, *++argv, 0, soup); | | 548 | (void)getaddr(RTA_GENMASK, *++argv, 0, soup); |
549 | break; | | 549 | break; |
550 | case K_GATEWAY: | | 550 | case K_GATEWAY: |
551 | if (!--argc) | | 551 | if (!--argc) |
552 | usage(1+*argv); | | 552 | usage(1+*argv); |
553 | (void)getaddr(RTA_GATEWAY, *++argv, 0, soup); | | 553 | (void)getaddr(RTA_GATEWAY, *++argv, 0, soup); |
554 | break; | | 554 | break; |
555 | case K_DST: | | 555 | case K_DST: |
556 | if (!--argc) | | 556 | if (!--argc) |
557 | usage(1+*argv); | | 557 | usage(1+*argv); |
558 | ishost = getaddr(RTA_DST, *++argv, &hp, soup); | | 558 | ishost = getaddr(RTA_DST, *++argv, &hp, soup); |
559 | dest = *argv; | | 559 | dest = *argv; |
560 | break; | | 560 | break; |
561 | case K_NETMASK: | | 561 | case K_NETMASK: |
562 | if (!--argc) | | 562 | if (!--argc) |
563 | usage(1+*argv); | | 563 | usage(1+*argv); |
564 | (void)getaddr(RTA_NETMASK, *++argv, 0, soup); | | 564 | (void)getaddr(RTA_NETMASK, *++argv, 0, soup); |
565 | /* FALLTHROUGH */ | | 565 | /* FALLTHROUGH */ |
566 | case K_NET: | | 566 | case K_NET: |
567 | forcenet++; | | 567 | forcenet++; |
568 | break; | | 568 | break; |
569 | case K_PREFIXLEN: | | 569 | case K_PREFIXLEN: |
570 | if (!--argc) | | 570 | if (!--argc) |
571 | usage(1+*argv); | | 571 | usage(1+*argv); |
572 | ishost = prefixlen(*++argv, soup); | | 572 | ishost = prefixlen(*++argv, soup); |
573 | break; | | 573 | break; |
574 | case K_MTU: | | 574 | case K_MTU: |
575 | case K_HOPCOUNT: | | 575 | case K_HOPCOUNT: |
576 | case K_EXPIRE: | | 576 | case K_EXPIRE: |
577 | case K_RECVPIPE: | | 577 | case K_RECVPIPE: |
578 | case K_SENDPIPE: | | 578 | case K_SENDPIPE: |
579 | case K_SSTHRESH: | | 579 | case K_SSTHRESH: |
580 | case K_RTT: | | 580 | case K_RTT: |
581 | case K_RTTVAR: | | 581 | case K_RTTVAR: |
582 | if (!--argc) | | 582 | if (!--argc) |
583 | usage(1+*argv); | | 583 | usage(1+*argv); |
584 | set_metric(*++argv, key); | | 584 | set_metric(*++argv, key); |
585 | break; | | 585 | break; |
586 | default: | | 586 | default: |
587 | usage(1+*argv); | | 587 | usage(1+*argv); |
588 | } | | 588 | } |
589 | } else { | | 589 | } else { |
590 | if ((rtm_addrs & RTA_DST) == 0) { | | 590 | if ((rtm_addrs & RTA_DST) == 0) { |
591 | dest = *argv; | | 591 | dest = *argv; |
592 | ishost = getaddr(RTA_DST, *argv, &hp, soup); | | 592 | ishost = getaddr(RTA_DST, *argv, &hp, soup); |
593 | } else if ((rtm_addrs & RTA_GATEWAY) == 0) { | | 593 | } else if ((rtm_addrs & RTA_GATEWAY) == 0) { |
594 | gateway = *argv; | | 594 | gateway = *argv; |
595 | (void)getaddr(RTA_GATEWAY, *argv, &hp, soup); | | 595 | (void)getaddr(RTA_GATEWAY, *argv, &hp, soup); |
596 | } else { | | 596 | } else { |
597 | ret = atoi(*argv); | | 597 | ret = atoi(*argv); |
598 | | | 598 | |
599 | if (ret == 0) { | | 599 | if (ret == 0) { |
600 | if (strcmp(*argv, "0") == 0) { | | 600 | if (strcmp(*argv, "0") == 0) { |
601 | if (!qflag) { | | 601 | if (!qflag) { |
602 | warnx("%s, %s", | | 602 | warnx("%s, %s", |
603 | "old usage of trailing 0", | | 603 | "old usage of trailing 0", |
604 | "assuming route to if"); | | 604 | "assuming route to if"); |
605 | } | | 605 | } |
606 | } else | | 606 | } else |
607 | usage(NULL); | | 607 | usage(NULL); |
608 | iflag = 1; | | 608 | iflag = 1; |
609 | continue; | | 609 | continue; |
610 | } else if (ret > 0 && ret < 10) { | | 610 | } else if (ret > 0 && ret < 10) { |
611 | if (!qflag) { | | 611 | if (!qflag) { |
612 | warnx("%s, %s", | | 612 | warnx("%s, %s", |
613 | "old usage of trailing digit", | | 613 | "old usage of trailing digit", |
614 | "assuming route via gateway"); | | 614 | "assuming route via gateway"); |
615 | } | | 615 | } |
616 | iflag = 0; | | 616 | iflag = 0; |
617 | continue; | | 617 | continue; |
618 | } | | 618 | } |
619 | (void)getaddr(RTA_NETMASK, *argv, 0, soup); | | 619 | (void)getaddr(RTA_NETMASK, *argv, 0, soup); |
620 | } | | 620 | } |
621 | } | | 621 | } |
622 | } | | 622 | } |
623 | if ((rtm_addrs & RTA_DST) == 0) | | 623 | if ((rtm_addrs & RTA_DST) == 0) |
624 | errx(EXIT_FAILURE, "missing destination specification"); | | 624 | errx(EXIT_FAILURE, "missing destination specification"); |
625 | if (*cmd == 'a' && (rtm_addrs & RTA_GATEWAY) == 0) | | 625 | if (*cmd == 'a' && (rtm_addrs & RTA_GATEWAY) == 0) |
626 | errx(EXIT_FAILURE, "missing gateway specification"); | | 626 | errx(EXIT_FAILURE, "missing gateway specification"); |
627 | if (forcehost && forcenet) | | 627 | if (forcehost && forcenet) |
628 | errx(EXIT_FAILURE, "-host and -net conflict"); | | 628 | errx(EXIT_FAILURE, "-host and -net conflict"); |
629 | else if (forcehost) | | 629 | else if (forcehost) |
630 | ishost = 1; | | 630 | ishost = 1; |
631 | else if (forcenet) | | 631 | else if (forcenet) |
632 | ishost = 0; | | 632 | ishost = 0; |
633 | flags |= RTF_UP; | | 633 | flags |= RTF_UP; |
634 | if (ishost) | | 634 | if (ishost) |
635 | flags |= RTF_HOST; | | 635 | flags |= RTF_HOST; |
636 | if (iflag == 0) | | 636 | if (iflag == 0) |
637 | flags |= RTF_GATEWAY; | | 637 | flags |= RTF_GATEWAY; |
638 | for (attempts = 1; ; attempts++) { | | 638 | for (attempts = 1; ; attempts++) { |
639 | errno = 0; | | 639 | errno = 0; |
640 | if ((ret = rtmsg(*cmd, flags, soup)) == 0) | | 640 | if ((ret = rtmsg(*cmd, flags, soup)) == 0) |
641 | break; | | 641 | break; |
642 | if (errno != ENETUNREACH && errno != ESRCH) | | 642 | if (errno != ENETUNREACH && errno != ESRCH) |
643 | break; | | 643 | break; |
644 | if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { | | 644 | if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { |
645 | hp->h_addr_list++; | | 645 | hp->h_addr_list++; |
646 | memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0], | | 646 | memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0], |
647 | hp->h_length); | | 647 | hp->h_length); |
648 | } else | | 648 | } else |
649 | break; | | 649 | break; |
650 | } | | 650 | } |
651 | if (*cmd == 'g' || qflag) | | 651 | if (*cmd == 'g' || qflag) |
652 | goto out; | | 652 | goto out; |
653 | | | 653 | |
654 | oerrno = errno; | | 654 | oerrno = errno; |
655 | (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest); | | 655 | (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest); |
656 | if (*gateway) { | | 656 | if (*gateway) { |
657 | (void)printf(": gateway %s", gateway); | | 657 | (void)printf(": gateway %s", gateway); |
658 | if (attempts > 1 && ret == 0 && af == AF_INET) | | 658 | if (attempts > 1 && ret == 0 && af == AF_INET) |
659 | (void)printf(" (%s)", | | 659 | (void)printf(" (%s)", |
660 | inet_ntoa(soup->so_gate->sin.sin_addr)); | | 660 | inet_ntoa(soup->so_gate->sin.sin_addr)); |
661 | } | | 661 | } |
662 | if (ret == 0) | | 662 | if (ret == 0) |
663 | (void)printf("\n"); | | 663 | (void)printf("\n"); |
664 | else | | 664 | else |
665 | (void)printf(": %s\n", route_strerror(oerrno)); | | 665 | (void)printf(": %s\n", route_strerror(oerrno)); |
666 | out: | | 666 | out: |
667 | free(sou.so_dst); | | 667 | free(sou.so_dst); |
668 | free(sou.so_gate); | | 668 | free(sou.so_gate); |
669 | free(sou.so_mask); | | 669 | free(sou.so_mask); |
670 | free(sou.so_genmask); | | 670 | free(sou.so_genmask); |
671 | free(sou.so_ifa); | | 671 | free(sou.so_ifa); |
672 | free(sou.so_ifp); | | 672 | free(sou.so_ifp); |
673 | free(sou.so_mpls); | | 673 | free(sou.so_mpls); |
674 | | | 674 | |
675 | return ret != 0; | | 675 | return ret != 0; |
676 | } | | 676 | } |
677 | | | 677 | |
678 | static void | | 678 | static void |
679 | inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin, | | 679 | inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin, |
680 | struct sou *soup) | | 680 | struct sou *soup) |
681 | { | | 681 | { |
682 | struct sockaddr_in *sin; | | 682 | struct sockaddr_in *sin; |
683 | u_int32_t addr, mask = 0; | | 683 | u_int32_t addr, mask = 0; |
684 | char *cp; | | 684 | char *cp; |
685 | | | 685 | |
686 | rtm_addrs |= RTA_NETMASK; | | 686 | rtm_addrs |= RTA_NETMASK; |
687 | if (net == 0) | | 687 | if (net == 0) |
688 | mask = addr = 0; | | 688 | mask = addr = 0; |
689 | else if (net < 128) { | | 689 | else if (net < 128) { |
690 | addr = net << IN_CLASSA_NSHIFT; | | 690 | addr = net << IN_CLASSA_NSHIFT; |
691 | mask = IN_CLASSA_NET; | | 691 | mask = IN_CLASSA_NET; |
692 | } else if (net < 192) { | | 692 | } else if (net < 192) { |
693 | addr = net << IN_CLASSA_NSHIFT; | | 693 | addr = net << IN_CLASSA_NSHIFT; |
694 | mask = IN_CLASSB_NET; | | 694 | mask = IN_CLASSB_NET; |
695 | } else if (net < 224) { | | 695 | } else if (net < 224) { |
696 | addr = net << IN_CLASSA_NSHIFT; | | 696 | addr = net << IN_CLASSA_NSHIFT; |
697 | mask = IN_CLASSC_NET; | | 697 | mask = IN_CLASSC_NET; |
698 | } else if (net < 256) { | | 698 | } else if (net < 256) { |
699 | addr = net << IN_CLASSA_NSHIFT; | | 699 | addr = net << IN_CLASSA_NSHIFT; |
700 | mask = IN_CLASSD_NET; | | 700 | mask = IN_CLASSD_NET; |
701 | } else if (net < 49152) { /* 192 * 256 */ | | 701 | } else if (net < 49152) { /* 192 * 256 */ |
702 | addr = net << IN_CLASSB_NSHIFT; | | 702 | addr = net << IN_CLASSB_NSHIFT; |
703 | mask = IN_CLASSB_NET; | | 703 | mask = IN_CLASSB_NET; |
704 | } else if (net < 57344) { /* 224 * 256 */ | | 704 | } else if (net < 57344) { /* 224 * 256 */ |
705 | addr = net << IN_CLASSB_NSHIFT; | | 705 | addr = net << IN_CLASSB_NSHIFT; |
706 | mask = IN_CLASSC_NET; | | 706 | mask = IN_CLASSC_NET; |
707 | } else if (net < 65536) { | | 707 | } else if (net < 65536) { |
708 | addr = net << IN_CLASSB_NSHIFT; | | 708 | addr = net << IN_CLASSB_NSHIFT; |
709 | mask = IN_CLASSB_NET; | | 709 | mask = IN_CLASSB_NET; |
710 | } else if (net < 14680064L) { /* 224 * 65536 */ | | 710 | } else if (net < 14680064L) { /* 224 * 65536 */ |
711 | addr = net << IN_CLASSC_NSHIFT; | | 711 | addr = net << IN_CLASSC_NSHIFT; |
712 | mask = IN_CLASSC_NET; | | 712 | mask = IN_CLASSC_NET; |
713 | } else if (net < 16777216L) { | | 713 | } else if (net < 16777216L) { |
714 | addr = net << IN_CLASSC_NSHIFT; | | 714 | addr = net << IN_CLASSC_NSHIFT; |
715 | mask = IN_CLASSD_NET; | | 715 | mask = IN_CLASSD_NET; |
716 | } else { | | 716 | } else { |
717 | addr = net; | | 717 | addr = net; |
718 | if ((addr & IN_CLASSA_HOST) == 0) | | 718 | if ((addr & IN_CLASSA_HOST) == 0) |
719 | mask = IN_CLASSA_NET; | | 719 | mask = IN_CLASSA_NET; |
720 | else if ((addr & IN_CLASSB_HOST) == 0) | | 720 | else if ((addr & IN_CLASSB_HOST) == 0) |
721 | mask = IN_CLASSB_NET; | | 721 | mask = IN_CLASSB_NET; |
722 | else if ((addr & IN_CLASSC_HOST) == 0) | | 722 | else if ((addr & IN_CLASSC_HOST) == 0) |
723 | mask = IN_CLASSC_NET; | | 723 | mask = IN_CLASSC_NET; |
724 | else | | 724 | else |
725 | mask = -1; | | 725 | mask = -1; |
726 | } | | 726 | } |
727 | isin->sin_addr.s_addr = htonl(addr); | | 727 | isin->sin_addr.s_addr = htonl(addr); |
728 | sin = &soup->so_mask->sin; | | 728 | sin = &soup->so_mask->sin; |
729 | sin->sin_addr.s_addr = htonl(mask); | | 729 | sin->sin_addr.s_addr = htonl(mask); |
730 | sin->sin_len = 0; | | 730 | sin->sin_len = 0; |
731 | sin->sin_family = 0; | | 731 | sin->sin_family = 0; |
732 | cp = (char *)(&sin->sin_addr + 1); | | 732 | cp = (char *)(&sin->sin_addr + 1); |
733 | while (*--cp == 0 && cp > (char *)sin) | | 733 | while (*--cp == 0 && cp > (char *)sin) |
734 | ; | | 734 | ; |
735 | sin->sin_len = 1 + cp - (char *)sin; | | 735 | sin->sin_len = 1 + cp - (char *)sin; |
736 | sin->sin_family = AF_INET; | | 736 | sin->sin_family = AF_INET; |
737 | } | | 737 | } |
738 | | | 738 | |
739 | #ifdef INET6 | | 739 | #ifdef INET6 |
740 | /* | | 740 | /* |
741 | * XXX the function may need more improvement... | | 741 | * XXX the function may need more improvement... |
742 | */ | | 742 | */ |
743 | static int | | 743 | static int |
744 | inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup) | | 744 | inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup) |
745 | { | | 745 | { |
746 | const char *plen; | | 746 | const char *plen; |
747 | struct in6_addr in6; | | 747 | struct in6_addr in6; |
748 | | | 748 | |
749 | plen = NULL; | | 749 | plen = NULL; |
750 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && | | 750 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && |
751 | sin6->sin6_scope_id == 0) { | | 751 | sin6->sin6_scope_id == 0) { |
752 | plen = "0"; | | 752 | plen = "0"; |
753 | } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { | | 753 | } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { |
754 | /* aggregatable global unicast - RFC2374 */ | | 754 | /* aggregatable global unicast - RFC2374 */ |
755 | memset(&in6, 0, sizeof(in6)); | | 755 | memset(&in6, 0, sizeof(in6)); |
756 | if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) | | 756 | if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) |
757 | plen = "64"; | | 757 | plen = "64"; |
758 | } | | 758 | } |
759 | | | 759 | |
760 | if (!plen || strcmp(plen, "128") == 0) | | 760 | if (!plen || strcmp(plen, "128") == 0) |
761 | return 1; | | 761 | return 1; |
762 | else { | | 762 | else { |
763 | rtm_addrs |= RTA_NETMASK; | | 763 | rtm_addrs |= RTA_NETMASK; |
764 | (void)prefixlen(plen, soup); | | 764 | (void)prefixlen(plen, soup); |
765 | return 0; | | 765 | return 0; |
766 | } | | 766 | } |
767 | } | | 767 | } |
768 | #endif | | 768 | #endif |
769 | | | 769 | |
770 | /* | | 770 | /* |
771 | * Interpret an argument as a network address of some kind, | | 771 | * Interpret an argument as a network address of some kind, |
772 | * returning 1 if a host address, 0 if a network address. | | 772 | * returning 1 if a host address, 0 if a network address. |
773 | */ | | 773 | */ |
774 | static int | | 774 | static int |
775 | getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup) | | 775 | getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup) |
776 | { | | 776 | { |
777 | sup su; | | 777 | sup su; |
778 | struct hostent *hp; | | 778 | struct hostent *hp; |
779 | struct netent *np; | | 779 | struct netent *np; |
780 | u_int32_t val; | | 780 | u_int32_t val; |
781 | char *t; | | 781 | char *t; |
782 | int afamily; /* local copy of af so we can change it */ | | 782 | int afamily; /* local copy of af so we can change it */ |
783 | | | 783 | |
784 | if (af == AF_UNSPEC) { | | 784 | if (af == AF_UNSPEC) { |
785 | af = AF_INET; | | 785 | af = AF_INET; |
786 | aflen = sizeof(struct sockaddr_in); | | 786 | aflen = sizeof(struct sockaddr_in); |
787 | } | | 787 | } |
788 | afamily = af; | | 788 | afamily = af; |
789 | rtm_addrs |= which; | | 789 | rtm_addrs |= which; |
790 | switch (which) { | | 790 | switch (which) { |
791 | case RTA_DST: | | 791 | case RTA_DST: |
792 | su = soup->so_dst; | | 792 | su = soup->so_dst; |
793 | break; | | 793 | break; |
794 | case RTA_GATEWAY: | | 794 | case RTA_GATEWAY: |
795 | su = soup->so_gate; | | 795 | su = soup->so_gate; |
796 | break; | | 796 | break; |
797 | case RTA_NETMASK: | | 797 | case RTA_NETMASK: |
798 | su = soup->so_mask; | | 798 | su = soup->so_mask; |
799 | break; | | 799 | break; |
800 | case RTA_GENMASK: | | 800 | case RTA_GENMASK: |
801 | su = soup->so_genmask; | | 801 | su = soup->so_genmask; |
802 | break; | | 802 | break; |
803 | case RTA_IFP: | | 803 | case RTA_IFP: |
804 | su = soup->so_ifp; | | 804 | su = soup->so_ifp; |
805 | afamily = AF_LINK; | | 805 | afamily = AF_LINK; |
806 | break; | | 806 | break; |
807 | case RTA_IFA: | | 807 | case RTA_IFA: |
808 | su = soup->so_ifa; | | 808 | su = soup->so_ifa; |
809 | su->sa.sa_family = af; | | 809 | su->sa.sa_family = af; |
810 | break; | | 810 | break; |
811 | #ifndef SMALL | | 811 | #ifndef SMALL |
812 | case RTA_TAG: | | 812 | case RTA_TAG: |
813 | su = soup->so_mpls; | | 813 | su = soup->so_mpls; |
814 | afamily = AF_MPLS; | | 814 | afamily = AF_MPLS; |
815 | break; | | 815 | break; |
816 | #endif | | 816 | #endif |
817 | default: | | 817 | default: |
818 | su = NULL; | | 818 | su = NULL; |
819 | usage("Internal Error"); | | 819 | usage("Internal Error"); |
820 | /*NOTREACHED*/ | | 820 | /*NOTREACHED*/ |
821 | } | | 821 | } |
822 | su->sa.sa_len = aflen; | | 822 | su->sa.sa_len = aflen; |
823 | su->sa.sa_family = afamily; /* cases that don't want it have left already */ | | 823 | su->sa.sa_family = afamily; /* cases that don't want it have left already */ |
824 | if (strcmp(s, "default") == 0) { | | 824 | if (strcmp(s, "default") == 0) { |
825 | switch (which) { | | 825 | switch (which) { |
826 | case RTA_DST: | | 826 | case RTA_DST: |
827 | forcenet++; | | 827 | forcenet++; |
828 | (void)getaddr(RTA_NETMASK, s, 0, soup); | | 828 | (void)getaddr(RTA_NETMASK, s, 0, soup); |
829 | break; | | 829 | break; |
830 | case RTA_NETMASK: | | 830 | case RTA_NETMASK: |
831 | case RTA_GENMASK: | | 831 | case RTA_GENMASK: |
832 | su->sa.sa_len = 0; | | 832 | su->sa.sa_len = 0; |
833 | } | | 833 | } |
834 | return 0; | | 834 | return 0; |
835 | } | | 835 | } |
836 | switch (afamily) { | | 836 | switch (afamily) { |
837 | #ifdef INET6 | | 837 | #ifdef INET6 |
838 | case AF_INET6: | | 838 | case AF_INET6: |
839 | { | | 839 | { |
840 | struct addrinfo hints, *res; | | 840 | struct addrinfo hints, *res; |
841 | char *slash = 0; | | 841 | char *slash = 0; |
842 | | | 842 | |
843 | if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0) | | 843 | if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0) |
844 | *slash = '\0'; | | 844 | *slash = '\0'; |
845 | memset(&hints, 0, sizeof(hints)); | | 845 | memset(&hints, 0, sizeof(hints)); |
846 | hints.ai_family = afamily; /*AF_INET6*/ | | 846 | hints.ai_family = afamily; /*AF_INET6*/ |
847 | hints.ai_flags = AI_NUMERICHOST; | | 847 | hints.ai_flags = AI_NUMERICHOST; |
848 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ | | 848 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
849 | if (getaddrinfo(s, "0", &hints, &res) != 0) { | | 849 | if (getaddrinfo(s, "0", &hints, &res) != 0) { |
850 | hints.ai_flags = 0; | | 850 | hints.ai_flags = 0; |
851 | if (slash) { | | 851 | if (slash) { |
852 | *slash = '/'; | | 852 | *slash = '/'; |
853 | slash = 0; | | 853 | slash = 0; |
854 | } | | 854 | } |
855 | if (getaddrinfo(s, "0", &hints, &res) != 0) | | 855 | if (getaddrinfo(s, "0", &hints, &res) != 0) |
856 | errx(EXIT_FAILURE, "%s: bad value", s); | | 856 | errx(EXIT_FAILURE, "%s: bad value", s); |
857 | } | | 857 | } |
858 | if (slash) | | 858 | if (slash) |
859 | *slash = '/'; | | 859 | *slash = '/'; |
860 | if (sizeof(su->sin6) != res->ai_addrlen) | | 860 | if (sizeof(su->sin6) != res->ai_addrlen) |
861 | errx(EXIT_FAILURE, "%s: bad value", s); | | 861 | errx(EXIT_FAILURE, "%s: bad value", s); |
862 | if (res->ai_next) { | | 862 | if (res->ai_next) { |
863 | errx(EXIT_FAILURE, | | 863 | errx(EXIT_FAILURE, |
864 | "%s: address resolved to multiple values", s); | | 864 | "%s: address resolved to multiple values", s); |
865 | } | | 865 | } |
866 | memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); | | 866 | memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); |
867 | freeaddrinfo(res); | | 867 | freeaddrinfo(res); |
868 | inet6_putscopeid(&su->sin6, INET6_IS_ADDR_LINKLOCAL| | | 868 | inet6_putscopeid(&su->sin6, INET6_IS_ADDR_LINKLOCAL| |
869 | INET6_IS_ADDR_MC_LINKLOCAL); | | 869 | INET6_IS_ADDR_MC_LINKLOCAL); |
870 | if (hints.ai_flags == AI_NUMERICHOST) { | | 870 | if (hints.ai_flags == AI_NUMERICHOST) { |
871 | if (slash) | | 871 | if (slash) |
872 | return prefixlen(slash + 1, soup); | | 872 | return prefixlen(slash + 1, soup); |
873 | if (which == RTA_DST) | | 873 | if (which == RTA_DST) |
874 | return inet6_makenetandmask(&su->sin6, soup); | | 874 | return inet6_makenetandmask(&su->sin6, soup); |
875 | return 0; | | 875 | return 0; |
876 | } else | | 876 | } else |
877 | return 1; | | 877 | return 1; |
878 | } | | 878 | } |
879 | #endif | | 879 | #endif |
880 | | | 880 | |
881 | case PF_ROUTE: | | 881 | case PF_ROUTE: |
882 | su->sa.sa_len = sizeof(*su); | | 882 | su->sa.sa_len = sizeof(*su); |
883 | sockaddr(s, &su->sa); | | 883 | sockaddr(s, &su->sa); |
884 | return 1; | | 884 | return 1; |
885 | | | 885 | |
886 | #ifndef SMALL | | 886 | #ifndef SMALL |
887 | case AF_APPLETALK: | | 887 | case AF_APPLETALK: |
888 | t = strchr (s, '.'); | | 888 | t = strchr (s, '.'); |
889 | if (!t) { | | 889 | if (!t) { |
890 | badataddr: | | 890 | badataddr: |
891 | errx(EXIT_FAILURE, "bad address: %s", s); | | 891 | errx(EXIT_FAILURE, "bad address: %s", s); |
892 | } | | 892 | } |
893 | val = atoi (s); | | 893 | val = atoi (s); |
894 | if (val > 65535) | | 894 | if (val > 65535) |
895 | goto badataddr; | | 895 | goto badataddr; |
896 | su->sat.sat_addr.s_net = val; | | 896 | su->sat.sat_addr.s_net = val; |
897 | val = atoi (t); | | 897 | val = atoi (t); |
898 | if (val > 256) | | 898 | if (val > 256) |
899 | goto badataddr; | | 899 | goto badataddr; |
900 | su->sat.sat_addr.s_node = val; | | 900 | su->sat.sat_addr.s_node = val; |
901 | rtm_addrs |= RTA_NETMASK; | | 901 | rtm_addrs |= RTA_NETMASK; |
902 | return(forcehost || su->sat.sat_addr.s_node != 0); | | 902 | return(forcehost || su->sat.sat_addr.s_node != 0); |
903 | case AF_MPLS: | | 903 | case AF_MPLS: |
904 | if (which == RTA_DST) | | 904 | if (which == RTA_DST) |
905 | soup->so_dst = readtag(su, s); | | 905 | soup->so_dst = readtag(su, s); |
906 | else if (which == RTA_TAG) | | 906 | else if (which == RTA_TAG) |
907 | soup->so_mpls = readtag(su, s); | | 907 | soup->so_mpls = readtag(su, s); |
908 | else | | 908 | else |
909 | errx(EXIT_FAILURE, "MPLS can be used only as " | | 909 | errx(EXIT_FAILURE, "MPLS can be used only as " |
910 | "DST or TAG"); | | 910 | "DST or TAG"); |
911 | return 1; | | 911 | return 1; |
912 | #endif | | 912 | #endif |
913 | | | 913 | |
914 | case AF_LINK: | | 914 | case AF_LINK: |
915 | link_addr(s, &su->sdl); | | 915 | link_addr(s, &su->sdl); |
916 | return 1; | | 916 | return 1; |
917 | | | 917 | |
918 | case AF_INET: | | 918 | case AF_INET: |
919 | default: | | 919 | default: |
920 | break; | | 920 | break; |
921 | } | | 921 | } |
922 | | | 922 | |
923 | if (hpp == NULL) | | 923 | if (hpp == NULL) |
924 | hpp = &hp; | | 924 | hpp = &hp; |
925 | *hpp = NULL; | | 925 | *hpp = NULL; |
926 | | | 926 | |
927 | if ((t = strchr(s, '/')) != NULL && which == RTA_DST) { | | 927 | if ((t = strchr(s, '/')) != NULL && which == RTA_DST) { |
928 | *t = '\0'; | | 928 | *t = '\0'; |
929 | if (forcenet == 0) { | | 929 | if (forcenet == 0) { |
930 | if ((val = inet_addr(s)) != INADDR_NONE) { | | 930 | if ((val = inet_addr(s)) != INADDR_NONE) { |
931 | inet_makenetandmask(htonl(val), &su->sin, soup); | | 931 | inet_makenetandmask(htonl(val), &su->sin, soup); |
932 | return prefixlen(&t[1], soup); | | 932 | return prefixlen(&t[1], soup); |
933 | } | | 933 | } |
934 | } else { | | 934 | } else { |
935 | if ((val = inet_network(s)) != INADDR_NONE) { | | 935 | if ((val = inet_network(s)) != INADDR_NONE) { |
936 | inet_makenetandmask(val, &su->sin, soup); | | 936 | inet_makenetandmask(val, &su->sin, soup); |
937 | return prefixlen(&t[1], soup); | | 937 | return prefixlen(&t[1], soup); |
938 | } | | 938 | } |
939 | } | | 939 | } |
940 | *t = '/'; | | 940 | *t = '/'; |
941 | } | | 941 | } |
942 | if (inet_aton(s, &su->sin.sin_addr) && | | 942 | if (inet_aton(s, &su->sin.sin_addr) && |
943 | (which != RTA_DST || forcenet == 0)) { | | 943 | (which != RTA_DST || forcenet == 0)) { |
944 | val = su->sin.sin_addr.s_addr; | | 944 | val = su->sin.sin_addr.s_addr; |
945 | if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) | | 945 | if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) |
946 | return 1; | | 946 | return 1; |
947 | else { | | 947 | else { |
948 | val = ntohl(val); | | 948 | val = ntohl(val); |
949 | goto netdone; | | 949 | goto netdone; |
950 | } | | 950 | } |
951 | } | | 951 | } |
952 | if ((val = inet_network(s)) != INADDR_NONE || | | 952 | if ((val = inet_network(s)) != INADDR_NONE || |
953 | ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) { | | 953 | ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) { |
954 | netdone: | | 954 | netdone: |
955 | if (which == RTA_DST) | | 955 | if (which == RTA_DST) |
956 | inet_makenetandmask(val, &su->sin, soup); | | 956 | inet_makenetandmask(val, &su->sin, soup); |
957 | return 0; | | 957 | return 0; |
958 | } | | 958 | } |
959 | hp = gethostbyname(s); | | 959 | hp = gethostbyname(s); |
960 | if (hp) { | | 960 | if (hp) { |
961 | *hpp = hp; | | 961 | *hpp = hp; |
962 | su->sin.sin_family = hp->h_addrtype; | | 962 | su->sin.sin_family = hp->h_addrtype; |
963 | memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length); | | 963 | memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length); |
964 | return 1; | | 964 | return 1; |
965 | } | | 965 | } |
966 | errx(EXIT_FAILURE, "%s: bad value", s); | | 966 | errx(EXIT_FAILURE, "%s: bad value", s); |
967 | /*NOTREACHED*/ | | 967 | /*NOTREACHED*/ |
968 | } | | 968 | } |
969 | | | 969 | |
970 | #ifndef SMALL | | 970 | #ifndef SMALL |
971 | static sup | | 971 | static sup |
972 | readtag(sup su, const char *s) | | 972 | readtag(sup su, const char *s) |
973 | { | | 973 | { |
974 | char *p, *n, *norig; | | 974 | char *p, *n, *norig; |
975 | int mplssize = 0; | | 975 | int mplssize = 0; |
976 | sup retsu = su; | | 976 | sup retsu = su; |
977 | | | 977 | |
978 | n = strdup(s); | | 978 | n = strdup(s); |
979 | if (n == NULL) | | 979 | if (n == NULL) |
980 | errx(EXIT_FAILURE, "%s: Cannot allocate memory", s); | | 980 | errx(EXIT_FAILURE, "%s: Cannot allocate memory", s); |
981 | norig = n; | | 981 | norig = n; |
982 | for (uint i = 0; i < strlen(n); i++) | | 982 | for (uint i = 0; i < strlen(n); i++) |
983 | if(n[i] == ',') | | 983 | if(n[i] == ',') |
984 | mplssize++; | | 984 | mplssize++; |
985 | | | 985 | |
986 | #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \ | | 986 | #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \ |
987 | mplssize * sizeof(union mpls_shim)) | | 987 | mplssize * sizeof(union mpls_shim)) |
988 | | | 988 | |
989 | if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) { | | 989 | if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) { |
990 | free(su); | | 990 | free(su); |
991 | retsu = malloc(MPLS_NEW_SIZE); | | 991 | retsu = malloc(MPLS_NEW_SIZE); |
992 | retsu->smpls.smpls_family = AF_MPLS; | | 992 | retsu->smpls.smpls_family = AF_MPLS; |
993 | } | | 993 | } |
994 | retsu->smpls.smpls_len = MPLS_NEW_SIZE; | | 994 | retsu->smpls.smpls_len = MPLS_NEW_SIZE; |
995 | mplssize = 0; | | 995 | mplssize = 0; |
996 | while ((p = strchr(n, ',')) != NULL) { | | 996 | while ((p = strchr(n, ',')) != NULL) { |
997 | p[0] = '\0'; | | 997 | p[0] = '\0'; |
998 | addtag(retsu, n, mplssize); | | 998 | addtag(retsu, n, mplssize); |
999 | n = p + 1; | | 999 | n = p + 1; |
1000 | mplssize++; | | 1000 | mplssize++; |
1001 | } | | 1001 | } |
1002 | addtag(retsu, n, mplssize); | | 1002 | addtag(retsu, n, mplssize); |
1003 | | | 1003 | |
1004 | free(norig); | | 1004 | free(norig); |
1005 | return retsu; | | 1005 | return retsu; |
1006 | } | | 1006 | } |
1007 | | | 1007 | |
1008 | static void | | 1008 | static void |
1009 | addtag(sup su, const char *s, int where) | | 1009 | addtag(sup su, const char *s, int where) |
1010 | { | | 1010 | { |
1011 | union mpls_shim *ms = &su->smpls.smpls_addr; | | 1011 | union mpls_shim *ms = &su->smpls.smpls_addr; |
1012 | | | 1012 | |
1013 | if (atoi(s) < 0 || atoi(s) >= (1 << 20)) | | 1013 | if (atoi(s) < 0 || atoi(s) >= (1 << 20)) |
1014 | errx(EXIT_FAILURE, "%s: Bad tag", s); | | 1014 | errx(EXIT_FAILURE, "%s: Bad tag", s); |
1015 | ms[where].s_addr = 0; | | 1015 | ms[where].s_addr = 0; |
1016 | ms[where].shim.label = atoi(s); | | 1016 | ms[where].shim.label = atoi(s); |
1017 | ms[where].s_addr = htonl(ms[where].s_addr); | | 1017 | ms[where].s_addr = htonl(ms[where].s_addr); |
1018 | } | | 1018 | } |
1019 | #endif /* SMALL */ | | 1019 | #endif /* SMALL */ |
1020 | | | 1020 | |
1021 | int | | 1021 | int |
1022 | prefixlen(const char *s, struct sou *soup) | | 1022 | prefixlen(const char *s, struct sou *soup) |
1023 | { | | 1023 | { |
1024 | int max, len = atoi(s); | | 1024 | int max, len = atoi(s); |
1025 | #ifdef INET6 | | 1025 | #ifdef INET6 |
1026 | int q, r; | | 1026 | int q, r; |
1027 | #endif | | 1027 | #endif |
1028 | | | 1028 | |
1029 | switch (af) { | | 1029 | switch (af) { |
1030 | case AF_INET: | | 1030 | case AF_INET: |
1031 | max = sizeof(struct in_addr) * 8; | | 1031 | max = sizeof(struct in_addr) * 8; |
1032 | break; | | 1032 | break; |
1033 | #ifdef INET6 | | 1033 | #ifdef INET6 |
1034 | case AF_INET6: | | 1034 | case AF_INET6: |
1035 | max = sizeof(struct in6_addr) * 8; | | 1035 | max = sizeof(struct in6_addr) * 8; |
1036 | break; | | 1036 | break; |
1037 | #endif | | 1037 | #endif |
1038 | default: | | 1038 | default: |
1039 | errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af); | | 1039 | errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af); |
1040 | /*NOTREACHED*/ | | 1040 | /*NOTREACHED*/ |
1041 | } | | 1041 | } |
1042 | | | 1042 | |
1043 | rtm_addrs |= RTA_NETMASK; | | 1043 | rtm_addrs |= RTA_NETMASK; |
1044 | if (len < -1 || len > max) | | 1044 | if (len < -1 || len > max) |
1045 | errx(EXIT_FAILURE, "%s: bad value", s); | | 1045 | errx(EXIT_FAILURE, "%s: bad value", s); |
1046 | | | 1046 | |
1047 | #ifdef INET6 | | 1047 | #ifdef INET6 |
1048 | q = len >> 3; | | 1048 | q = len >> 3; |
1049 | r = len & 7; | | 1049 | r = len & 7; |
1050 | #endif | | 1050 | #endif |
1051 | switch (af) { | | 1051 | switch (af) { |
1052 | case AF_INET: | | 1052 | case AF_INET: |
1053 | memset(soup->so_mask, 0, sizeof(*soup->so_mask)); | | 1053 | memset(soup->so_mask, 0, sizeof(*soup->so_mask)); |
1054 | soup->so_mask->sin.sin_family = AF_INET; | | 1054 | soup->so_mask->sin.sin_family = AF_INET; |
1055 | soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in); | | 1055 | soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in); |
1056 | soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0 | | 1056 | soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0 |
1057 | : htonl(0xffffffff << (32 - len))); | | 1057 | : htonl(0xffffffff << (32 - len))); |
1058 | break; | | 1058 | break; |
1059 | #ifdef INET6 | | 1059 | #ifdef INET6 |
1060 | case AF_INET6: | | 1060 | case AF_INET6: |
1061 | soup->so_mask->sin6.sin6_family = AF_INET6; | | 1061 | soup->so_mask->sin6.sin6_family = AF_INET6; |
1062 | soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6); | | 1062 | soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6); |
1063 | memset(&soup->so_mask->sin6.sin6_addr, 0, | | 1063 | memset(&soup->so_mask->sin6.sin6_addr, 0, |
1064 | sizeof(soup->so_mask->sin6.sin6_addr)); | | 1064 | sizeof(soup->so_mask->sin6.sin6_addr)); |
1065 | if (q > 0) | | 1065 | if (q > 0) |
1066 | memset(&soup->so_mask->sin6.sin6_addr, 0xff, q); | | 1066 | memset(&soup->so_mask->sin6.sin6_addr, 0xff, q); |
1067 | if (r > 0) | | 1067 | if (r > 0) |
1068 | *((u_char *)&soup->so_mask->sin6.sin6_addr + q) = | | 1068 | *((u_char *)&soup->so_mask->sin6.sin6_addr + q) = |
1069 | (0xff00 >> r) & 0xff; | | 1069 | (0xff00 >> r) & 0xff; |
1070 | break; | | 1070 | break; |
1071 | #endif | | 1071 | #endif |
1072 | } | | 1072 | } |
1073 | return len == max; | | 1073 | return len == max; |
1074 | } | | 1074 | } |
1075 | | | 1075 | |
1076 | #ifndef SMALL | | 1076 | #ifndef SMALL |
1077 | static void | | 1077 | static void |
1078 | interfaces(void) | | 1078 | interfaces(void) |
1079 | { | | 1079 | { |
1080 | size_t needed; | | 1080 | size_t needed; |
1081 | int mib[6]; | | 1081 | int mib[6]; |
1082 | char *buf, *lim, *next; | | 1082 | char *buf, *lim, *next; |
1083 | struct rt_msghdr *rtm; | | 1083 | struct rt_msghdr *rtm; |
1084 | | | 1084 | |
1085 | mib[0] = CTL_NET; | | 1085 | mib[0] = CTL_NET; |
1086 | mib[1] = PF_ROUTE; | | 1086 | mib[1] = PF_ROUTE; |
1087 | mib[2] = 0; /* protocol */ | | 1087 | mib[2] = 0; /* protocol */ |
1088 | mib[3] = 0; /* wildcard address family */ | | 1088 | mib[3] = 0; /* wildcard address family */ |
1089 | mib[4] = NET_RT_IFLIST; | | 1089 | mib[4] = NET_RT_IFLIST; |
1090 | mib[5] = 0; /* no flags */ | | 1090 | mib[5] = 0; /* no flags */ |
1091 | if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | | 1091 | if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) |
1092 | err(EXIT_FAILURE, "route-sysctl-estimate"); | | 1092 | err(EXIT_FAILURE, "route-sysctl-estimate"); |
1093 | if (needed) { | | 1093 | if (needed) { |
1094 | if ((buf = malloc(needed)) == NULL) | | 1094 | if ((buf = malloc(needed)) == NULL) |
1095 | err(EXIT_FAILURE, "malloc"); | | 1095 | err(EXIT_FAILURE, "malloc"); |
1096 | if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { | | 1096 | if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { |
1097 | err(EXIT_FAILURE, | | 1097 | err(EXIT_FAILURE, |
1098 | "actual retrieval of interface table"); | | 1098 | "actual retrieval of interface table"); |
1099 | } | | 1099 | } |
1100 | lim = buf + needed; | | 1100 | lim = buf + needed; |
1101 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | | 1101 | for (next = buf; next < lim; next += rtm->rtm_msglen) { |
1102 | rtm = (struct rt_msghdr *)next; | | 1102 | rtm = (struct rt_msghdr *)next; |
1103 | print_rtmsg(rtm, rtm->rtm_msglen); | | 1103 | print_rtmsg(rtm, rtm->rtm_msglen); |
1104 | } | | 1104 | } |
1105 | free(buf); | | 1105 | free(buf); |
1106 | } | | 1106 | } |
1107 | } | | 1107 | } |
1108 | | | 1108 | |
1109 | static void | | 1109 | static void |
1110 | monitor(int argc, char * const *argv) | | 1110 | monitor(int argc, char * const *argv) |
1111 | { | | 1111 | { |
1112 | int i, n; | | 1112 | int i, n; |
1113 | union { | | 1113 | union { |
1114 | char msg[2048]; | | 1114 | char msg[2048]; |
1115 | struct rt_msghdr hdr; | | 1115 | struct rt_msghdr hdr; |
1116 | } u; | | 1116 | } u; |
1117 | int count = 0; | | 1117 | int count = 0; |
1118 | | | 1118 | |
1119 | /* usage: route monitor [-c <count>] */ | | 1119 | /* usage: route monitor [-c <count>] */ |
1120 | | | 1120 | |
1121 | /* eat "monitor" */ | | 1121 | /* eat "monitor" */ |
1122 | argc -= 1; | | 1122 | argc -= 1; |
1123 | argv += 1; | | 1123 | argv += 1; |
1124 | | | 1124 | |
1125 | /* parse [-c <count>] */ | | 1125 | /* parse [-c <count>] */ |
1126 | if (argc > 0) { | | 1126 | if (argc > 0) { |
1127 | if (argc != 2) | | 1127 | if (argc != 2) |
1128 | usage(argv[0]); | | 1128 | usage(argv[0]); |
1129 | if (strcmp(argv[0], "-c") != 0) | | 1129 | if (strcmp(argv[0], "-c") != 0) |
1130 | usage(argv[0]); | | 1130 | usage(argv[0]); |
1131 | | | 1131 | |
1132 | count = atoi(argv[1]); | | 1132 | count = atoi(argv[1]); |
1133 | } | | 1133 | } |
1134 | | | 1134 | |
1135 | verbose = 1; | | 1135 | verbose = 1; |
1136 | if (debugonly) { | | 1136 | if (debugonly) { |
1137 | interfaces(); | | 1137 | interfaces(); |
1138 | exit(0); | | 1138 | exit(0); |
1139 | } | | 1139 | } |
1140 | for(i = 0; count == 0 || i < count; i++) { | | 1140 | for(i = 0; count == 0 || i < count; i++) { |
1141 | time_t now; | | 1141 | time_t now; |
1142 | n = prog_read(sock, &u, sizeof(u)); | | 1142 | n = prog_read(sock, &u, sizeof(u)); |
1143 | if (n == -1) { | | 1143 | if (n == -1) { |
1144 | warn("read"); | | 1144 | warn("read"); |
1145 | continue; | | 1145 | continue; |
1146 | } | | 1146 | } |
1147 | now = time(NULL); | | 1147 | now = time(NULL); |
1148 | (void)printf("got message of size %d on %s", n, ctime(&now)); | | 1148 | (void)printf("got message of size %d on %s", n, ctime(&now)); |
1149 | print_rtmsg(&u.hdr, n); | | 1149 | print_rtmsg(&u.hdr, n); |
1150 | } | | 1150 | } |
1151 | } | | 1151 | } |
1152 | | | 1152 | |
1153 | #endif /* SMALL */ | | 1153 | #endif /* SMALL */ |
1154 | | | 1154 | |
1155 | | | 1155 | |
1156 | struct { | | 1156 | struct { |
1157 | struct rt_msghdr m_rtm; | | 1157 | struct rt_msghdr m_rtm; |
1158 | char m_space[512]; | | 1158 | char m_space[512]; |
1159 | } m_rtmsg; | | 1159 | } m_rtmsg; |
1160 | | | 1160 | |
1161 | static int | | 1161 | static int |
1162 | rtmsg(int cmd, int flags, struct sou *soup) | | 1162 | rtmsg(int cmd, int flags, struct sou *soup) |
1163 | { | | 1163 | { |
1164 | static int seq; | | 1164 | static int seq; |
1165 | int rlen; | | 1165 | int rlen; |
1166 | char *cp = m_rtmsg.m_space; | | 1166 | char *cp = m_rtmsg.m_space; |
1167 | int l; | | 1167 | int l; |
1168 | | | 1168 | |
1169 | #define NEXTADDR(w, u) \ | | 1169 | #define NEXTADDR(w, u) \ |
1170 | if (rtm_addrs & (w)) {\ | | 1170 | if (rtm_addrs & (w)) {\ |
1171 | l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\ | | 1171 | l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\ |
1172 | if (verbose && ! shortoutput) sodump(u,#u);\ | | 1172 | if (verbose && ! shortoutput) sodump(u,#u);\ |
1173 | } | | 1173 | } |
1174 | | | 1174 | |
1175 | errno = 0; | | 1175 | errno = 0; |
1176 | memset(&m_rtmsg, 0, sizeof(m_rtmsg)); | | 1176 | memset(&m_rtmsg, 0, sizeof(m_rtmsg)); |
1177 | if (cmd == 'a') | | 1177 | if (cmd == 'a') |
1178 | cmd = RTM_ADD; | | 1178 | cmd = RTM_ADD; |
1179 | else if (cmd == 'c') | | 1179 | else if (cmd == 'c') |
1180 | cmd = RTM_CHANGE; | | 1180 | cmd = RTM_CHANGE; |
1181 | else if (cmd == 'g') { | | 1181 | else if (cmd == 'g') { |
1182 | #ifdef SMALL | | 1182 | #ifdef SMALL |
1183 | return -1; | | 1183 | return -1; |
1184 | #else /* SMALL */ | | 1184 | #else /* SMALL */ |
1185 | cmd = RTM_GET; | | 1185 | cmd = RTM_GET; |
1186 | if (soup->so_ifp->sa.sa_family == AF_UNSPEC) { | | 1186 | if (soup->so_ifp->sa.sa_family == AF_UNSPEC) { |
1187 | soup->so_ifp->sa.sa_family = AF_LINK; | | 1187 | soup->so_ifp->sa.sa_family = AF_LINK; |
1188 | soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl); | | 1188 | soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl); |
1189 | rtm_addrs |= RTA_IFP; | | 1189 | rtm_addrs |= RTA_IFP; |
1190 | } | | 1190 | } |
1191 | #endif /* SMALL */ | | 1191 | #endif /* SMALL */ |
1192 | } else | | 1192 | } else |
1193 | cmd = RTM_DELETE; | | 1193 | cmd = RTM_DELETE; |
1194 | #define rtm m_rtmsg.m_rtm | | 1194 | #define rtm m_rtmsg.m_rtm |
1195 | rtm.rtm_type = cmd; | | 1195 | rtm.rtm_type = cmd; |
1196 | rtm.rtm_flags = flags; | | 1196 | rtm.rtm_flags = flags; |
1197 | rtm.rtm_version = RTM_VERSION; | | 1197 | rtm.rtm_version = RTM_VERSION; |
1198 | rtm.rtm_seq = ++seq; | | 1198 | rtm.rtm_seq = ++seq; |
1199 | rtm.rtm_addrs = rtm_addrs; | | 1199 | rtm.rtm_addrs = rtm_addrs; |
1200 | rtm.rtm_rmx = rt_metrics; | | 1200 | rtm.rtm_rmx = rt_metrics; |
1201 | rtm.rtm_inits = rtm_inits; | | 1201 | rtm.rtm_inits = rtm_inits; |
1202 | | | 1202 | |
1203 | if (rtm_addrs & RTA_NETMASK) | | 1203 | if (rtm_addrs & RTA_NETMASK) |
1204 | mask_addr(soup); | | 1204 | mask_addr(soup); |
1205 | NEXTADDR(RTA_DST, soup->so_dst); | | 1205 | NEXTADDR(RTA_DST, soup->so_dst); |
1206 | NEXTADDR(RTA_GATEWAY, soup->so_gate); | | 1206 | NEXTADDR(RTA_GATEWAY, soup->so_gate); |
1207 | NEXTADDR(RTA_NETMASK, soup->so_mask); | | 1207 | NEXTADDR(RTA_NETMASK, soup->so_mask); |
1208 | NEXTADDR(RTA_GENMASK, soup->so_genmask); | | 1208 | NEXTADDR(RTA_GENMASK, soup->so_genmask); |
1209 | NEXTADDR(RTA_IFP, soup->so_ifp); | | 1209 | NEXTADDR(RTA_IFP, soup->so_ifp); |
1210 | NEXTADDR(RTA_IFA, soup->so_ifa); | | 1210 | NEXTADDR(RTA_IFA, soup->so_ifa); |
1211 | #ifndef SMALL | | 1211 | #ifndef SMALL |
1212 | NEXTADDR(RTA_TAG, soup->so_mpls); | | 1212 | NEXTADDR(RTA_TAG, soup->so_mpls); |
1213 | #endif | | 1213 | #endif |
1214 | rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; | | 1214 | rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; |
1215 | if (verbose && ! shortoutput) { | | 1215 | if (verbose && ! shortoutput) { |
1216 | if (rtm_addrs) | | 1216 | if (rtm_addrs) |
1217 | putchar('\n'); | | 1217 | putchar('\n'); |
1218 | print_rtmsg(&rtm, l); | | 1218 | print_rtmsg(&rtm, l); |
1219 | } | | 1219 | } |
1220 | if (debugonly) | | 1220 | if (debugonly) |
1221 | return 0; | | 1221 | return 0; |
1222 | do { | | 1222 | do { |
1223 | rlen = prog_write(sock, (char *)&m_rtmsg, l); | | 1223 | rlen = prog_write(sock, (char *)&m_rtmsg, l); |
1224 | } while (rlen == -1 && errno == ENOBUFS); | | 1224 | } while (rlen == -1 && errno == ENOBUFS); |
1225 | if (rlen == -1) { | | 1225 | if (rlen == -1) { |
1226 | warnx("writing to routing socket: %s", route_strerror(errno)); | | 1226 | warnx("writing to routing socket: %s", route_strerror(errno)); |
1227 | return -1; | | 1227 | return -1; |
1228 | } | | 1228 | } |
1229 | if (rlen < l) { | | 1229 | if (rlen < l) { |
1230 | warnx("write to routing socket, got %d for rlen", rlen); | | 1230 | warnx("write to routing socket, got %d for rlen", rlen); |
1231 | return 1; | | 1231 | return 1; |
1232 | } | | 1232 | } |
1233 | #ifndef SMALL | | 1233 | #ifndef SMALL |
1234 | if (cmd == RTM_GET) { | | 1234 | if (cmd == RTM_GET) { |
1235 | do { | | 1235 | do { |
1236 | l = prog_read(sock, | | 1236 | l = prog_read(sock, |
1237 | (char *)&m_rtmsg, sizeof(m_rtmsg)); | | 1237 | (char *)&m_rtmsg, sizeof(m_rtmsg)); |
1238 | } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); | | 1238 | } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); |
1239 | if (l < 0) | | 1239 | if (l < 0) |
1240 | err(EXIT_FAILURE, "read from routing socket"); | | 1240 | err(EXIT_FAILURE, "read from routing socket"); |
1241 | else | | 1241 | else |
1242 | return print_getmsg(&rtm, l, soup); | | 1242 | return print_getmsg(&rtm, l, soup); |
1243 | } | | 1243 | } |
1244 | #endif /* SMALL */ | | 1244 | #endif /* SMALL */ |
1245 | #undef rtm | | 1245 | #undef rtm |
1246 | return 0; | | 1246 | return 0; |
1247 | } | | 1247 | } |
1248 | | | 1248 | |
1249 | static void | | 1249 | static void |
1250 | mask_addr(struct sou *soup) | | 1250 | mask_addr(struct sou *soup) |
1251 | { | | 1251 | { |
1252 | int olen = soup->so_mask->sa.sa_len; | | 1252 | int olen = soup->so_mask->sa.sa_len; |
1253 | char *cp1 = olen + (char *)soup->so_mask, *cp2; | | 1253 | char *cp1 = olen + (char *)soup->so_mask, *cp2; |
1254 | | | 1254 | |
1255 | for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)soup->so_mask; ) | | 1255 | for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)soup->so_mask; ) |
1256 | if (*--cp1 != 0) { | | 1256 | if (*--cp1 != 0) { |
1257 | soup->so_mask->sa.sa_len = 1 + cp1 - (char *)soup->so_mask; | | 1257 | soup->so_mask->sa.sa_len = 1 + cp1 - (char *)soup->so_mask; |
1258 | break; | | 1258 | break; |
1259 | } | | 1259 | } |
1260 | if ((rtm_addrs & RTA_DST) == 0) | | 1260 | if ((rtm_addrs & RTA_DST) == 0) |
1261 | return; | | 1261 | return; |
1262 | switch (soup->so_dst->sa.sa_family) { | | 1262 | switch (soup->so_dst->sa.sa_family) { |
1263 | case AF_INET: | | 1263 | case AF_INET: |
1264 | #ifdef INET6 | | 1264 | #ifdef INET6 |
1265 | case AF_INET6: | | 1265 | case AF_INET6: |
1266 | #endif | | 1266 | #endif |
1267 | #ifndef SMALL | | 1267 | #ifndef SMALL |
1268 | case AF_APPLETALK: | | 1268 | case AF_APPLETALK: |
1269 | #endif /* SMALL */ | | 1269 | #endif /* SMALL */ |
1270 | case 0: | | 1270 | case 0: |
1271 | return; | | 1271 | return; |
1272 | } | | 1272 | } |
1273 | cp1 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_dst; | | 1273 | cp1 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_dst; |
1274 | cp2 = soup->so_dst->sa.sa_len + 1 + (char *)soup->so_dst; | | 1274 | cp2 = soup->so_dst->sa.sa_len + 1 + (char *)soup->so_dst; |
1275 | while (cp2 > cp1) | | 1275 | while (cp2 > cp1) |
1276 | *--cp2 = 0; | | 1276 | *--cp2 = 0; |
1277 | cp2 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_mask; | | 1277 | cp2 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_mask; |
1278 | while (cp1 > soup->so_dst->sa.sa_data) | | 1278 | while (cp1 > soup->so_dst->sa.sa_data) |
1279 | *--cp1 &= *--cp2; | | 1279 | *--cp1 &= *--cp2; |
1280 | } | | 1280 | } |
1281 | | | 1281 | |
1282 | const char * const msgtypes[] = { | | 1282 | const char * const msgtypes[] = { |
1283 | [RTM_ADD] = "RTM_ADD: Add Route", | | 1283 | [RTM_ADD] = "RTM_ADD: Add Route", |
1284 | [RTM_DELETE] = "RTM_DELETE: Delete Route", | | 1284 | [RTM_DELETE] = "RTM_DELETE: Delete Route", |
1285 | [RTM_CHANGE] = "RTM_CHANGE: Change Metrics, Flags or Gateway", | | 1285 | [RTM_CHANGE] = "RTM_CHANGE: Change Metrics, Flags or Gateway", |
1286 | [RTM_GET] = "RTM_GET: Report Metrics", | | 1286 | [RTM_GET] = "RTM_GET: Report Metrics", |
1287 | [RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning", | | 1287 | [RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning", |
1288 | [RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route", | | 1288 | [RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route", |
1289 | [RTM_MISS] = "RTM_MISS: Lookup failed on this address", | | 1289 | [RTM_MISS] = "RTM_MISS: Lookup failed on this address", |
1290 | [RTM_LOCK] = "RTM_LOCK: fix specified metrics", | | 1290 | [RTM_LOCK] = "RTM_LOCK: fix specified metrics", |
1291 | [RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT", | | 1291 | [RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT", |
1292 | [RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT", | | 1292 | [RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT", |
1293 | [RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface", | | 1293 | [RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface", |
1294 | [RTM_DELADDR] = "RTM_DELADDR: address being removed from iface", | | 1294 | [RTM_DELADDR] = "RTM_DELADDR: address being removed from iface", |
1295 | [RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)", | | 1295 | [RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)", |
1296 | [RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)", | | 1296 | [RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)", |
1297 | [RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure", | | 1297 | [RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure", |
1298 | [RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event", | | 1298 | [RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event", |
1299 | [RTM_IFINFO] = "RTM_IFINFO: iface status change", | | 1299 | [RTM_IFINFO] = "RTM_IFINFO: iface status change", |
1300 | [RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface", | | 1300 | [RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface", |
1301 | }; | | 1301 | }; |
1302 | | | 1302 | |
1303 | const char metricnames[] = | | 1303 | const char metricnames[] = |
1304 | "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; | | 1304 | "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; |
1305 | const char routeflags[] = | | 1305 | const char routeflags[] = |
1306 | "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CONNECTED\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1\023LOCAL\024BROADCAST"; | | 1306 | "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CONNECTED\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1\023LOCAL\024BROADCAST"; |
1307 | const char ifnetflags[] = | | 1307 | const char ifnetflags[] = |
1308 | "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; | | 1308 | "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; |
1309 | const char addrnames[] = | | 1309 | const char addrnames[] = |
1310 | "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG"; | | 1310 | "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG"; |
1311 | | | 1311 | |
1312 | | | 1312 | |
1313 | #ifndef SMALL | | 1313 | #ifndef SMALL |
1314 | static const char * | | 1314 | static const char * |
1315 | linkstate(struct if_msghdr *ifm) | | 1315 | linkstate(struct if_msghdr *ifm) |
1316 | { | | 1316 | { |
1317 | static char buf[64]; | | 1317 | static char buf[64]; |
1318 | | | 1318 | |
1319 | switch (ifm->ifm_data.ifi_link_state) { | | 1319 | switch (ifm->ifm_data.ifi_link_state) { |
1320 | case LINK_STATE_UNKNOWN: | | 1320 | case LINK_STATE_UNKNOWN: |
1321 | return "carrier: unknown"; | | 1321 | return "carrier: unknown"; |
1322 | case LINK_STATE_DOWN: | | 1322 | case LINK_STATE_DOWN: |
1323 | return "carrier: no carrier"; | | 1323 | return "carrier: no carrier"; |
1324 | case LINK_STATE_UP: | | 1324 | case LINK_STATE_UP: |
1325 | return "carrier: active"; | | 1325 | return "carrier: active"; |
1326 | default: | | 1326 | default: |
1327 | (void)snprintf(buf, sizeof(buf), "carrier: 0x%x", | | 1327 | (void)snprintf(buf, sizeof(buf), "carrier: 0x%x", |
1328 | ifm->ifm_data.ifi_link_state); | | 1328 | ifm->ifm_data.ifi_link_state); |
1329 | return buf; | | 1329 | return buf; |
1330 | } | | 1330 | } |
1331 | } | | 1331 | } |
1332 | #endif /* SMALL */ | | 1332 | #endif /* SMALL */ |
1333 | | | 1333 | |
1334 | static void | | 1334 | static void |
1335 | print_rtmsg(struct rt_msghdr *rtm, int msglen) | | 1335 | print_rtmsg(struct rt_msghdr *rtm, int msglen) |
1336 | { | | 1336 | { |
1337 | struct if_msghdr *ifm; | | 1337 | struct if_msghdr *ifm; |
1338 | struct ifa_msghdr *ifam; | | 1338 | struct ifa_msghdr *ifam; |
1339 | struct if_announcemsghdr *ifan; | | 1339 | struct if_announcemsghdr *ifan; |
1340 | union { | | 1340 | union { |
1341 | struct ieee80211_join_event join; | | 1341 | struct ieee80211_join_event join; |
1342 | struct ieee80211_leave_event leave; | | 1342 | struct ieee80211_leave_event leave; |
1343 | struct ieee80211_replay_event replay; | | 1343 | struct ieee80211_replay_event replay; |
1344 | struct ieee80211_michael_event michael; | | 1344 | struct ieee80211_michael_event michael; |
1345 | } ev; | | 1345 | } ev; |
1346 | size_t evlen = 0; | | 1346 | size_t evlen = 0; |
1347 | | | 1347 | |
1348 | if (verbose == 0) | | 1348 | if (verbose == 0) |
1349 | return; | | 1349 | return; |
1350 | if (rtm->rtm_version != RTM_VERSION) { | | 1350 | if (rtm->rtm_version != RTM_VERSION) { |
1351 | (void)printf("routing message version %d not understood\n", | | 1351 | (void)printf("routing message version %d not understood\n", |
1352 | rtm->rtm_version); | | 1352 | rtm->rtm_version); |
1353 | return; | | 1353 | return; |
1354 | } | | 1354 | } |
1355 | if (msgtypes[rtm->rtm_type]) | | 1355 | if (msgtypes[rtm->rtm_type]) |
1356 | (void)printf("%s: ", msgtypes[rtm->rtm_type]); | | 1356 | (void)printf("%s: ", msgtypes[rtm->rtm_type]); |
1357 | else | | 1357 | else |
1358 | (void)printf("#%d: ", rtm->rtm_type); | | 1358 | (void)printf("#%d: ", rtm->rtm_type); |
1359 | (void)printf("len %d, ", rtm->rtm_msglen); | | 1359 | (void)printf("len %d, ", rtm->rtm_msglen); |
1360 | switch (rtm->rtm_type) { | | 1360 | switch (rtm->rtm_type) { |
1361 | case RTM_IFINFO: | | 1361 | case RTM_IFINFO: |
1362 | ifm = (struct if_msghdr *)rtm; | | 1362 | ifm = (struct if_msghdr *)rtm; |
1363 | (void)printf("if# %d, %s, flags: ", ifm->ifm_index, | | 1363 | (void)printf("if# %d, %s, flags: ", ifm->ifm_index, |
1364 | #ifdef SMALL | | 1364 | #ifdef SMALL |
1365 | "" | | 1365 | "" |
1366 | #else | | 1366 | #else |
1367 | linkstate(ifm) | | 1367 | linkstate(ifm) |
1368 | #endif /* SMALL */ | | 1368 | #endif /* SMALL */ |
1369 | ); | | 1369 | ); |
1370 | bprintf(stdout, ifm->ifm_flags, ifnetflags); | | 1370 | bprintf(stdout, ifm->ifm_flags, ifnetflags); |
1371 | pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); | | 1371 | pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); |
1372 | break; | | 1372 | break; |
1373 | case RTM_NEWADDR: | | 1373 | case RTM_NEWADDR: |
1374 | case RTM_DELADDR: | | 1374 | case RTM_DELADDR: |
1375 | case RTM_CHGADDR: | | 1375 | case RTM_CHGADDR: |
1376 | ifam = (struct ifa_msghdr *)rtm; | | 1376 | ifam = (struct ifa_msghdr *)rtm; |
1377 | (void)printf("pid %d, metric %d, flags: ", | | 1377 | (void)printf("pid %d, metric %d, flags: ", |
1378 | ifam->ifam_pid, ifam->ifam_metric); | | 1378 | ifam->ifam_pid, ifam->ifam_metric); |
1379 | bprintf(stdout, ifam->ifam_flags, routeflags); | | 1379 | bprintf(stdout, ifam->ifam_flags, routeflags); |
1380 | pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); | | 1380 | pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); |
1381 | break; | | 1381 | break; |
1382 | case RTM_IEEE80211: | | 1382 | case RTM_IEEE80211: |
1383 | ifan = (struct if_announcemsghdr *)rtm; | | 1383 | ifan = (struct if_announcemsghdr *)rtm; |
1384 | (void)printf("if# %d, what: ", ifan->ifan_index); | | 1384 | (void)printf("if# %d, what: ", ifan->ifan_index); |
1385 | switch (ifan->ifan_what) { | | 1385 | switch (ifan->ifan_what) { |
1386 | case RTM_IEEE80211_ASSOC: | | 1386 | case RTM_IEEE80211_ASSOC: |
1387 | printf("associate"); | | 1387 | printf("associate"); |
1388 | break; | | 1388 | break; |
1389 | case RTM_IEEE80211_REASSOC: | | 1389 | case RTM_IEEE80211_REASSOC: |
1390 | printf("re-associate"); | | 1390 | printf("re-associate"); |
1391 | break; | | 1391 | break; |
1392 | case RTM_IEEE80211_DISASSOC: | | 1392 | case RTM_IEEE80211_DISASSOC: |
1393 | printf("disassociate"); | | 1393 | printf("disassociate"); |
1394 | break; | | 1394 | break; |
1395 | case RTM_IEEE80211_SCAN: | | 1395 | case RTM_IEEE80211_SCAN: |
1396 | printf("scan complete"); | | 1396 | printf("scan complete"); |
1397 | break; | | 1397 | break; |
1398 | case RTM_IEEE80211_JOIN: | | 1398 | case RTM_IEEE80211_JOIN: |
1399 | evlen = sizeof(ev.join); | | 1399 | evlen = sizeof(ev.join); |
1400 | printf("join"); | | 1400 | printf("join"); |
1401 | break; | | 1401 | break; |
1402 | case RTM_IEEE80211_LEAVE: | | 1402 | case RTM_IEEE80211_LEAVE: |
1403 | evlen = sizeof(ev.leave); | | 1403 | evlen = sizeof(ev.leave); |
1404 | printf("leave"); | | 1404 | printf("leave"); |
1405 | break; | | 1405 | break; |
1406 | case RTM_IEEE80211_MICHAEL: | | 1406 | case RTM_IEEE80211_MICHAEL: |
1407 | evlen = sizeof(ev.michael); | | 1407 | evlen = sizeof(ev.michael); |
1408 | printf("michael"); | | 1408 | printf("michael"); |
1409 | break; | | 1409 | break; |
1410 | case RTM_IEEE80211_REPLAY: | | 1410 | case RTM_IEEE80211_REPLAY: |
1411 | evlen = sizeof(ev.replay); | | 1411 | evlen = sizeof(ev.replay); |
1412 | printf("replay"); | | 1412 | printf("replay"); |
1413 | break; | | 1413 | break; |
1414 | default: | | 1414 | default: |
1415 | evlen = 0; | | 1415 | evlen = 0; |
1416 | printf("#%d", ifan->ifan_what); | | 1416 | printf("#%d", ifan->ifan_what); |
1417 | break; | | 1417 | break; |
1418 | } | | 1418 | } |
1419 | if (sizeof(*ifan) + evlen > ifan->ifan_msglen) { | | 1419 | if (sizeof(*ifan) + evlen > ifan->ifan_msglen) { |
1420 | printf(" (truncated)\n"); | | 1420 | printf(" (truncated)\n"); |
1421 | break; | | 1421 | break; |
1422 | } | | 1422 | } |
1423 | (void)memcpy(&ev, (ifan + 1), evlen); | | 1423 | (void)memcpy(&ev, (ifan + 1), evlen); |
1424 | switch (ifan->ifan_what) { | | 1424 | switch (ifan->ifan_what) { |
1425 | case RTM_IEEE80211_JOIN: | | 1425 | case RTM_IEEE80211_JOIN: |
1426 | case RTM_IEEE80211_LEAVE: | | 1426 | case RTM_IEEE80211_LEAVE: |
1427 | printf(" mac %" PRIETHER, | | 1427 | printf(" mac %" PRIETHER, |
1428 | PRIETHER_ARGS(ev.join.iev_addr)); | | 1428 | PRIETHER_ARGS(ev.join.iev_addr)); |
1429 | break; | | 1429 | break; |
1430 | case RTM_IEEE80211_REPLAY: | | 1430 | case RTM_IEEE80211_REPLAY: |
1431 | case RTM_IEEE80211_MICHAEL: | | 1431 | case RTM_IEEE80211_MICHAEL: |
1432 | printf(" src %" PRIETHER " dst %" PRIETHER | | 1432 | printf(" src %" PRIETHER " dst %" PRIETHER |
1433 | " cipher %" PRIu8 " keyix %" PRIu8, | | 1433 | " cipher %" PRIu8 " keyix %" PRIu8, |
1434 | PRIETHER_ARGS(ev.replay.iev_src), | | 1434 | PRIETHER_ARGS(ev.replay.iev_src), |
1435 | PRIETHER_ARGS(ev.replay.iev_dst), | | 1435 | PRIETHER_ARGS(ev.replay.iev_dst), |
1436 | ev.replay.iev_cipher, | | 1436 | ev.replay.iev_cipher, |
1437 | ev.replay.iev_keyix); | | 1437 | ev.replay.iev_keyix); |
1438 | if (ifan->ifan_what == RTM_IEEE80211_REPLAY) { | | 1438 | if (ifan->ifan_what == RTM_IEEE80211_REPLAY) { |
1439 | printf(" key rsc %#" PRIx64 | | 1439 | printf(" key rsc %#" PRIx64 |
1440 | " frame rsc %#" PRIx64, | | 1440 | " frame rsc %#" PRIx64, |
1441 | ev.replay.iev_keyrsc, ev.replay.iev_rsc); | | 1441 | ev.replay.iev_keyrsc, ev.replay.iev_rsc); |
1442 | } | | 1442 | } |
1443 | break; | | 1443 | break; |
1444 | default: | | 1444 | default: |
1445 | break; | | 1445 | break; |
1446 | } | | 1446 | } |
1447 | printf("\n"); | | 1447 | printf("\n"); |
1448 | break; | | 1448 | break; |
1449 | case RTM_IFANNOUNCE: | | 1449 | case RTM_IFANNOUNCE: |
1450 | ifan = (struct if_announcemsghdr *)rtm; | | 1450 | ifan = (struct if_announcemsghdr *)rtm; |
1451 | (void)printf("if# %d, what: ", ifan->ifan_index); | | 1451 | (void)printf("if# %d, what: ", ifan->ifan_index); |
1452 | switch (ifan->ifan_what) { | | 1452 | switch (ifan->ifan_what) { |
1453 | case IFAN_ARRIVAL: | | 1453 | case IFAN_ARRIVAL: |
1454 | printf("arrival"); | | 1454 | printf("arrival"); |
1455 | break; | | 1455 | break; |
1456 | case IFAN_DEPARTURE: | | 1456 | case IFAN_DEPARTURE: |
1457 | printf("departure"); | | 1457 | printf("departure"); |
1458 | break; | | 1458 | break; |
1459 | default: | | 1459 | default: |
1460 | printf("#%d", ifan->ifan_what); | | 1460 | printf("#%d", ifan->ifan_what); |
1461 | break; | | 1461 | break; |
1462 | } | | 1462 | } |
1463 | printf("\n"); | | 1463 | printf("\n"); |
1464 | break; | | 1464 | break; |
1465 | default: | | 1465 | case RTM_ADD: |
| | | 1466 | case RTM_DELETE: |
| | | 1467 | case RTM_GET: |
1466 | (void)printf("pid %d, seq %d, errno %d, flags: ", | | 1468 | (void)printf("pid %d, seq %d, errno %d, flags: ", |
1467 | rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); | | 1469 | rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); |
1468 | bprintf(stdout, rtm->rtm_flags, routeflags); | | 1470 | bprintf(stdout, rtm->rtm_flags, routeflags); |
1469 | pmsg_common(rtm); | | 1471 | pmsg_common(rtm); |
| | | 1472 | break; |
1470 | } | | 1473 | } |
1471 | } | | 1474 | } |
1472 | | | 1475 | |
1473 | #ifndef SMALL | | 1476 | #ifndef SMALL |
1474 | static int | | 1477 | static int |
1475 | print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup) | | 1478 | print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup) |
1476 | { | | 1479 | { |
1477 | struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL; | | 1480 | struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL; |
1478 | struct sockaddr_dl *ifp = NULL; | | 1481 | struct sockaddr_dl *ifp = NULL; |
1479 | struct sockaddr *sa; | | 1482 | struct sockaddr *sa; |
1480 | char *cp; | | 1483 | char *cp; |
1481 | int i; | | 1484 | int i; |
1482 | | | 1485 | |
1483 | if (! shortoutput) { | | 1486 | if (! shortoutput) { |
1484 | (void)printf(" route to: %s\n", | | 1487 | (void)printf(" route to: %s\n", |
1485 | routename(&soup->so_dst->sa, nflag)); | | 1488 | routename(&soup->so_dst->sa, nflag)); |
1486 | } | | 1489 | } |
1487 | if (rtm->rtm_version != RTM_VERSION) { | | 1490 | if (rtm->rtm_version != RTM_VERSION) { |
1488 | warnx("routing message version %d not understood", | | 1491 | warnx("routing message version %d not understood", |
1489 | rtm->rtm_version); | | 1492 | rtm->rtm_version); |
1490 | return 1; | | 1493 | return 1; |
1491 | } | | 1494 | } |
1492 | if (rtm->rtm_msglen > msglen) { | | 1495 | if (rtm->rtm_msglen > msglen) { |
1493 | warnx("message length mismatch, in packet %d, returned %d", | | 1496 | warnx("message length mismatch, in packet %d, returned %d", |
1494 | rtm->rtm_msglen, msglen); | | 1497 | rtm->rtm_msglen, msglen); |
1495 | } | | 1498 | } |
1496 | if (rtm->rtm_errno) { | | 1499 | if (rtm->rtm_errno) { |
1497 | warnx("RTM_GET: %s (errno %d)", | | 1500 | warnx("RTM_GET: %s (errno %d)", |
1498 | strerror(rtm->rtm_errno), rtm->rtm_errno); | | 1501 | strerror(rtm->rtm_errno), rtm->rtm_errno); |
1499 | return 1; | | 1502 | return 1; |
1500 | } | | 1503 | } |
1501 | cp = ((char *)(rtm + 1)); | | 1504 | cp = ((char *)(rtm + 1)); |
1502 | if (rtm->rtm_addrs) | | 1505 | if (rtm->rtm_addrs) |
1503 | for (i = 1; i; i <<= 1) | | 1506 | for (i = 1; i; i <<= 1) |
1504 | if (i & rtm->rtm_addrs) { | | 1507 | if (i & rtm->rtm_addrs) { |
1505 | sa = (struct sockaddr *)cp; | | 1508 | sa = (struct sockaddr *)cp; |
1506 | switch (i) { | | 1509 | switch (i) { |
1507 | case RTA_DST: | | 1510 | case RTA_DST: |
1508 | dst = sa; | | 1511 | dst = sa; |
1509 | break; | | 1512 | break; |
1510 | case RTA_GATEWAY: | | 1513 | case RTA_GATEWAY: |
1511 | gate = sa; | | 1514 | gate = sa; |
1512 | break; | | 1515 | break; |
1513 | case RTA_NETMASK: | | 1516 | case RTA_NETMASK: |
1514 | mask = sa; | | 1517 | mask = sa; |
1515 | break; | | 1518 | break; |
1516 | case RTA_IFP: | | 1519 | case RTA_IFP: |
1517 | if (sa->sa_family == AF_LINK && | | 1520 | if (sa->sa_family == AF_LINK && |
1518 | ((struct sockaddr_dl *)sa)->sdl_nlen) | | 1521 | ((struct sockaddr_dl *)sa)->sdl_nlen) |
1519 | ifp = (struct sockaddr_dl *)sa; | | 1522 | ifp = (struct sockaddr_dl *)sa; |
1520 | break; | | 1523 | break; |
1521 | case RTA_IFA: | | 1524 | case RTA_IFA: |
1522 | ifa = sa; | | 1525 | ifa = sa; |
1523 | break; | | 1526 | break; |
1524 | case RTA_TAG: | | 1527 | case RTA_TAG: |
1525 | mpls = sa; | | 1528 | mpls = sa; |
1526 | break; | | 1529 | break; |
1527 | } | | 1530 | } |
1528 | RT_ADVANCE(cp, sa); | | 1531 | RT_ADVANCE(cp, sa); |
1529 | } | | 1532 | } |
1530 | if (dst && mask) | | 1533 | if (dst && mask) |
1531 | mask->sa_family = dst->sa_family; /* XXX */ | | 1534 | mask->sa_family = dst->sa_family; /* XXX */ |
1532 | if (dst && ! shortoutput) | | 1535 | if (dst && ! shortoutput) |
1533 | (void)printf("destination: %s\n", | | 1536 | (void)printf("destination: %s\n", |
1534 | routename(dst, nflag)); | | 1537 | routename(dst, nflag)); |
1535 | if (mask && ! shortoutput) { | | 1538 | if (mask && ! shortoutput) { |
1536 | int savenflag = nflag; | | 1539 | int savenflag = nflag; |
1537 | | | 1540 | |
1538 | nflag = RT_NFLAG; | | 1541 | nflag = RT_NFLAG; |
1539 | (void)printf(" mask: %s\n", | | 1542 | (void)printf(" mask: %s\n", |
1540 | routename(mask, nflag)); | | 1543 | routename(mask, nflag)); |
1541 | nflag = savenflag; | | 1544 | nflag = savenflag; |
1542 | } | | 1545 | } |
1543 | if (gate && rtm->rtm_flags & RTF_GATEWAY) { | | 1546 | if (gate && rtm->rtm_flags & RTF_GATEWAY) { |
1544 | const char *name; | | 1547 | const char *name; |
1545 | | | 1548 | |
1546 | name = routename(gate, nflag); | | 1549 | name = routename(gate, nflag); |
1547 | if (shortoutput) { | | 1550 | if (shortoutput) { |
1548 | if (*name == '\0') | | 1551 | if (*name == '\0') |
1549 | return 1; | | 1552 | return 1; |
1550 | (void)printf("%s\n", name); | | 1553 | (void)printf("%s\n", name); |
1551 | } else | | 1554 | } else |
1552 | (void)printf(" gateway: %s\n", name); | | 1555 | (void)printf(" gateway: %s\n", name); |
1553 | } | | 1556 | } |
1554 | if (mpls) { | | 1557 | if (mpls) { |
1555 | const char *name; | | 1558 | const char *name; |
1556 | name = routename(mpls, nflag); | | 1559 | name = routename(mpls, nflag); |
1557 | if(shortoutput) { | | 1560 | if(shortoutput) { |
1558 | if (*name == '\0') | | 1561 | if (*name == '\0') |
1559 | return 1; | | 1562 | return 1; |
1560 | printf("%s\n", name); | | 1563 | printf("%s\n", name); |
1561 | } else | | 1564 | } else |
1562 | printf(" Tag: %s\n", name); | | 1565 | printf(" Tag: %s\n", name); |
1563 | } | | 1566 | } |
1564 | | | 1567 | |
1565 | if (ifa && ! shortoutput) | | 1568 | if (ifa && ! shortoutput) |
1566 | (void)printf(" local addr: %s\n", | | 1569 | (void)printf(" local addr: %s\n", |
1567 | routename(ifa, nflag)); | | 1570 | routename(ifa, nflag)); |
1568 | if (ifp && ! shortoutput) | | 1571 | if (ifp && ! shortoutput) |
1569 | (void)printf(" interface: %.*s\n", | | 1572 | (void)printf(" interface: %.*s\n", |
1570 | ifp->sdl_nlen, ifp->sdl_data); | | 1573 | ifp->sdl_nlen, ifp->sdl_data); |
1571 | if (! shortoutput) { | | 1574 | if (! shortoutput) { |
1572 | (void)printf(" flags: "); | | 1575 | (void)printf(" flags: "); |
1573 | bprintf(stdout, rtm->rtm_flags, routeflags); | | 1576 | bprintf(stdout, rtm->rtm_flags, routeflags); |
1574 | } | | 1577 | } |
1575 | | | 1578 | |
1576 | #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') | | 1579 | #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') |
1577 | #define msec(u) (((u) + 500) / 1000) /* usec to msec */ | | 1580 | #define msec(u) (((u) + 500) / 1000) /* usec to msec */ |
1578 | | | 1581 | |
1579 | if (! shortoutput) { | | 1582 | if (! shortoutput) { |
1580 | (void)printf("\n%s\n", "\ | | 1583 | (void)printf("\n%s\n", "\ |
1581 | recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); | | 1584 | recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); |
1582 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); | | 1585 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); |
1583 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); | | 1586 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); |
1584 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); | | 1587 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); |
1585 | printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); | | 1588 | printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); |
1586 | printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); | | 1589 | printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); |
1587 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); | | 1590 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); |
1588 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); | | 1591 | printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); |
1589 | if (rtm->rtm_rmx.rmx_expire) | | 1592 | if (rtm->rtm_rmx.rmx_expire) |
1590 | rtm->rtm_rmx.rmx_expire -= time(0); | | 1593 | rtm->rtm_rmx.rmx_expire -= time(0); |
1591 | printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); | | 1594 | printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); |
1592 | } | | 1595 | } |
1593 | #undef lock | | 1596 | #undef lock |
1594 | #undef msec | | 1597 | #undef msec |
1595 | #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) | | 1598 | #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) |
1596 | | | 1599 | |
1597 | if (shortoutput) | | 1600 | if (shortoutput) |
1598 | return (rtm->rtm_addrs & RTF_GATEWAY) == 0; | | 1601 | return (rtm->rtm_addrs & RTF_GATEWAY) == 0; |
1599 | else if (verbose) | | 1602 | else if (verbose) |
1600 | pmsg_common(rtm); | | 1603 | pmsg_common(rtm); |
1601 | else if (rtm->rtm_addrs &~ RTA_IGN) { | | 1604 | else if (rtm->rtm_addrs &~ RTA_IGN) { |
1602 | (void)printf("sockaddrs: "); | | 1605 | (void)printf("sockaddrs: "); |
1603 | bprintf(stdout, rtm->rtm_addrs, addrnames); | | 1606 | bprintf(stdout, rtm->rtm_addrs, addrnames); |
1604 | putchar('\n'); | | 1607 | putchar('\n'); |
1605 | } | | 1608 | } |
1606 | return 0; | | 1609 | return 0; |
1607 | #undef RTA_IGN | | 1610 | #undef RTA_IGN |
1608 | } | | 1611 | } |
1609 | #endif /* SMALL */ | | 1612 | #endif /* SMALL */ |
1610 | | | 1613 | |
1611 | void | | 1614 | void |
1612 | pmsg_common(struct rt_msghdr *rtm) | | 1615 | pmsg_common(struct rt_msghdr *rtm) |
1613 | { | | 1616 | { |
1614 | (void)printf("\nlocks: "); | | 1617 | (void)printf("\nlocks: "); |
1615 | bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); | | 1618 | bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); |
1616 | (void)printf(" inits: "); | | 1619 | (void)printf(" inits: "); |
1617 | bprintf(stdout, rtm->rtm_inits, metricnames); | | 1620 | bprintf(stdout, rtm->rtm_inits, metricnames); |
1618 | pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs); | | 1621 | pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs); |
1619 | } | | 1622 | } |
1620 | | | 1623 | |
1621 | static void | | 1624 | static void |
1622 | extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp) | | 1625 | extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp) |
1623 | { | | 1626 | { |
1624 | int i, nmf = -1; | | 1627 | int i, nmf = -1; |
1625 | | | 1628 | |
1626 | for (i = 0; i < RTAX_MAX; i++) { | | 1629 | for (i = 0; i < RTAX_MAX; i++) { |
1627 | if ((1 << i) & addrs) { | | 1630 | if ((1 << i) & addrs) { |
1628 | sa[i] = (const struct sockaddr *)cp; | | 1631 | sa[i] = (const struct sockaddr *)cp; |
1629 | if ((i == RTAX_DST || i == RTAX_IFA) && | | 1632 | if ((i == RTAX_DST || i == RTAX_IFA) && |
1630 | nmf == -1) | | 1633 | nmf == -1) |
1631 | nmf = sa[i]->sa_family; | | 1634 | nmf = sa[i]->sa_family; |
1632 | RT_ADVANCE(cp, sa[i]); | | 1635 | RT_ADVANCE(cp, sa[i]); |
1633 | } else | | 1636 | } else |
1634 | sa[i] = NULL; | | 1637 | sa[i] = NULL; |
1635 | } | | 1638 | } |
1636 | | | 1639 | |
1637 | if (nmfp != NULL) | | 1640 | if (nmfp != NULL) |
1638 | *nmfp = nmf; | | 1641 | *nmfp = nmf; |
1639 | } | | 1642 | } |
1640 | | | 1643 | |
1641 | static void | | 1644 | static void |
1642 | pmsg_addrs(const char *cp, int addrs) | | 1645 | pmsg_addrs(const char *cp, int addrs) |
1643 | { | | 1646 | { |
1644 | const struct sockaddr *sa[RTAX_MAX]; | | 1647 | const struct sockaddr *sa[RTAX_MAX]; |
1645 | int i, nmf; | | 1648 | int i, nmf; |
1646 | | | 1649 | |
1647 | if (addrs != 0) { | | 1650 | if (addrs != 0) { |
1648 | (void)printf("\nsockaddrs: "); | | 1651 | (void)printf("\nsockaddrs: "); |
1649 | bprintf(stdout, addrs, addrnames); | | 1652 | bprintf(stdout, addrs, addrnames); |
1650 | (void)putchar('\n'); | | 1653 | (void)putchar('\n'); |
1651 | extract_addrs(cp, addrs, sa, &nmf); | | 1654 | extract_addrs(cp, addrs, sa, &nmf); |
1652 | for (i = 0; i < RTAX_MAX; i++) { | | 1655 | for (i = 0; i < RTAX_MAX; i++) { |
1653 | if (sa[i] == NULL) | | 1656 | if (sa[i] == NULL) |
1654 | continue; | | 1657 | continue; |
1655 | | | 1658 | |
1656 | if (i == RTAX_NETMASK && sa[i]->sa_len) | | 1659 | if (i == RTAX_NETMASK && sa[i]->sa_len) |
1657 | (void)printf(" %s", | | 1660 | (void)printf(" %s", |
1658 | netmask_string(sa[i], -1, nmf)); | | 1661 | netmask_string(sa[i], -1, nmf)); |
1659 | else | | 1662 | else |
1660 | (void)printf(" %s", | | 1663 | (void)printf(" %s", |
1661 | routename(sa[i], nflag)); | | 1664 | routename(sa[i], nflag)); |
1662 | } | | 1665 | } |
1663 | } | | 1666 | } |
1664 | (void)putchar('\n'); | | 1667 | (void)putchar('\n'); |
1665 | (void)fflush(stdout); | | 1668 | (void)fflush(stdout); |
1666 | } | | 1669 | } |
1667 | | | 1670 | |
1668 | static void | | 1671 | static void |
1669 | bprintf(FILE *fp, int b, const char *f) | | 1672 | bprintf(FILE *fp, int b, const char *f) |
1670 | { | | 1673 | { |
1671 | int i; | | 1674 | int i; |
1672 | int gotsome = 0; | | 1675 | int gotsome = 0; |
1673 | const uint8_t *s = (const uint8_t *)f; | | 1676 | const uint8_t *s = (const uint8_t *)f; |
1674 | | | 1677 | |
1675 | if (b == 0) { | | 1678 | if (b == 0) { |
1676 | fputs("none", fp); | | 1679 | fputs("none", fp); |
1677 | return; | | 1680 | return; |
1678 | } | | 1681 | } |
1679 | while ((i = *s++) != 0) { | | 1682 | while ((i = *s++) != 0) { |
1680 | if (b & (1 << (i-1))) { | | 1683 | if (b & (1 << (i-1))) { |
1681 | if (gotsome == 0) | | 1684 | if (gotsome == 0) |
1682 | i = '<'; | | 1685 | i = '<'; |
1683 | else | | 1686 | else |
1684 | i = ','; | | 1687 | i = ','; |
1685 | (void)putc(i, fp); | | 1688 | (void)putc(i, fp); |
1686 | gotsome = 1; | | 1689 | gotsome = 1; |
1687 | for (; (i = *s) > 32; s++) | | 1690 | for (; (i = *s) > 32; s++) |
1688 | (void)putc(i, fp); | | 1691 | (void)putc(i, fp); |
1689 | } else | | 1692 | } else |
1690 | while (*s > 32) | | 1693 | while (*s > 32) |
1691 | s++; | | 1694 | s++; |
1692 | } | | 1695 | } |
1693 | if (gotsome) | | 1696 | if (gotsome) |
1694 | (void)putc('>', fp); | | 1697 | (void)putc('>', fp); |
1695 | } | | 1698 | } |
1696 | | | 1699 | |
1697 | int | | 1700 | int |
1698 | keyword(const char *cp) | | 1701 | keyword(const char *cp) |
1699 | { | | 1702 | { |
1700 | struct keytab *kt = keywords; | | 1703 | struct keytab *kt = keywords; |
1701 | | | 1704 | |
1702 | while (kt->kt_cp && strcmp(kt->kt_cp, cp)) | | 1705 | while (kt->kt_cp && strcmp(kt->kt_cp, cp)) |
1703 | kt++; | | 1706 | kt++; |
1704 | return kt->kt_i; | | 1707 | return kt->kt_i; |
1705 | } | | 1708 | } |
1706 | | | 1709 | |
1707 | static void | | 1710 | static void |
1708 | sodump(sup su, const char *which) | | 1711 | sodump(sup su, const char *which) |
1709 | { | | 1712 | { |
1710 | #ifdef INET6 | | 1713 | #ifdef INET6 |
1711 | char ntop_buf[NI_MAXHOST]; | | 1714 | char ntop_buf[NI_MAXHOST]; |
1712 | #endif | | 1715 | #endif |
1713 | | | 1716 | |
1714 | switch (su->sa.sa_family) { | | 1717 | switch (su->sa.sa_family) { |
1715 | case AF_INET: | | 1718 | case AF_INET: |
1716 | (void)printf("%s: inet %s; ", | | 1719 | (void)printf("%s: inet %s; ", |
1717 | which, inet_ntoa(su->sin.sin_addr)); | | 1720 | which, inet_ntoa(su->sin.sin_addr)); |
1718 | break; | | 1721 | break; |
1719 | #ifndef SMALL | | 1722 | #ifndef SMALL |
1720 | case AF_APPLETALK: | | 1723 | case AF_APPLETALK: |
1721 | (void)printf("%s: atalk %d.%d; ", | | 1724 | (void)printf("%s: atalk %d.%d; ", |
1722 | which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node); | | 1725 | which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node); |
1723 | break; | | 1726 | break; |
1724 | #endif | | 1727 | #endif |
1725 | case AF_LINK: | | 1728 | case AF_LINK: |
1726 | (void)printf("%s: link %s; ", | | 1729 | (void)printf("%s: link %s; ", |
1727 | which, link_ntoa(&su->sdl)); | | 1730 | which, link_ntoa(&su->sdl)); |
1728 | break; | | 1731 | break; |
1729 | #ifdef INET6 | | 1732 | #ifdef INET6 |
1730 | case AF_INET6: | | 1733 | case AF_INET6: |
1731 | (void)printf("%s: inet6 %s; ", | | 1734 | (void)printf("%s: inet6 %s; ", |
1732 | which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, | | 1735 | which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, |
1733 | ntop_buf, sizeof(ntop_buf))); | | 1736 | ntop_buf, sizeof(ntop_buf))); |
1734 | break; | | 1737 | break; |
1735 | #endif | | 1738 | #endif |
1736 | #ifndef SMALL | | 1739 | #ifndef SMALL |
1737 | case AF_MPLS: | | 1740 | case AF_MPLS: |
1738 | { | | 1741 | { |
1739 | union mpls_shim ms; | | 1742 | union mpls_shim ms; |
1740 | const union mpls_shim *pms; | | 1743 | const union mpls_shim *pms; |
1741 | int psize = sizeof(struct sockaddr_mpls); | | 1744 | int psize = sizeof(struct sockaddr_mpls); |
1742 | | | 1745 | |
1743 | ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr); | | 1746 | ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr); |
1744 | printf("%s: mpls %u; ", | | 1747 | printf("%s: mpls %u; ", |
1745 | which, ms.shim.label); | | 1748 | which, ms.shim.label); |
1746 | | | 1749 | |
1747 | pms = &su->smpls.smpls_addr; | | 1750 | pms = &su->smpls.smpls_addr; |
1748 | while(psize < su->smpls.smpls_len) { | | 1751 | while(psize < su->smpls.smpls_len) { |
1749 | pms++; | | 1752 | pms++; |
1750 | ms.s_addr = ntohl(pms->s_addr); | | 1753 | ms.s_addr = ntohl(pms->s_addr); |
1751 | printf("%u; ", ms.shim.label); | | 1754 | printf("%u; ", ms.shim.label); |
1752 | psize += sizeof(ms); | | 1755 | psize += sizeof(ms); |
1753 | } | | 1756 | } |
1754 | break; | | 1757 | break; |
1755 | } | | 1758 | } |
1756 | #endif /* SMALL */ | | 1759 | #endif /* SMALL */ |
1757 | default: | | 1760 | default: |
1758 | (void)printf("%s: (%d) %s; ", | | 1761 | (void)printf("%s: (%d) %s; ", |
1759 | which, su->sa.sa_family, any_ntoa(&su->sa)); | | 1762 | which, su->sa.sa_family, any_ntoa(&su->sa)); |
1760 | } | | 1763 | } |
1761 | (void)fflush(stdout); | | 1764 | (void)fflush(stdout); |
1762 | } | | 1765 | } |
1763 | | | 1766 | |
1764 | /* States*/ | | 1767 | /* States*/ |
1765 | #define VIRGIN 0 | | 1768 | #define VIRGIN 0 |
1766 | #define GOTONE 1 | | 1769 | #define GOTONE 1 |
1767 | #define GOTTWO 2 | | 1770 | #define GOTTWO 2 |
1768 | /* Inputs */ | | 1771 | /* Inputs */ |
1769 | #define DIGIT (4*0) | | 1772 | #define DIGIT (4*0) |
1770 | #define END (4*1) | | 1773 | #define END (4*1) |
1771 | #define DELIM (4*2) | | 1774 | #define DELIM (4*2) |
1772 | | | 1775 | |
1773 | static void | | 1776 | static void |
1774 | sockaddr(const char *addr, struct sockaddr *sa) | | 1777 | sockaddr(const char *addr, struct sockaddr *sa) |
1775 | { | | 1778 | { |
1776 | char *cp = (char *)sa; | | 1779 | char *cp = (char *)sa; |
1777 | int size = sa->sa_len; | | 1780 | int size = sa->sa_len; |
1778 | char *cplim = cp + size; | | 1781 | char *cplim = cp + size; |
1779 | int byte = 0, state = VIRGIN, new = 0; | | 1782 | int byte = 0, state = VIRGIN, new = 0; |
1780 | | | 1783 | |
1781 | (void)memset(cp, 0, size); | | 1784 | (void)memset(cp, 0, size); |
1782 | cp++; | | 1785 | cp++; |
1783 | do { | | 1786 | do { |
1784 | if ((*addr >= '0') && (*addr <= '9')) { | | 1787 | if ((*addr >= '0') && (*addr <= '9')) { |
1785 | new = *addr - '0'; | | 1788 | new = *addr - '0'; |
1786 | } else if ((*addr >= 'a') && (*addr <= 'f')) { | | 1789 | } else if ((*addr >= 'a') && (*addr <= 'f')) { |
1787 | new = *addr - 'a' + 10; | | 1790 | new = *addr - 'a' + 10; |
1788 | } else if ((*addr >= 'A') && (*addr <= 'F')) { | | 1791 | } else if ((*addr >= 'A') && (*addr <= 'F')) { |
1789 | new = *addr - 'A' + 10; | | 1792 | new = *addr - 'A' + 10; |
1790 | } else if (*addr == 0) | | 1793 | } else if (*addr == 0) |
1791 | state |= END; | | 1794 | state |= END; |
1792 | else | | 1795 | else |
1793 | state |= DELIM; | | 1796 | state |= DELIM; |
1794 | addr++; | | 1797 | addr++; |
1795 | switch (state /* | INPUT */) { | | 1798 | switch (state /* | INPUT */) { |
1796 | case GOTTWO | DIGIT: | | 1799 | case GOTTWO | DIGIT: |
1797 | *cp++ = byte; /*FALLTHROUGH*/ | | 1800 | *cp++ = byte; /*FALLTHROUGH*/ |
1798 | case VIRGIN | DIGIT: | | 1801 | case VIRGIN | DIGIT: |
1799 | state = GOTONE; byte = new; continue; | | 1802 | state = GOTONE; byte = new; continue; |
1800 | case GOTONE | DIGIT: | | 1803 | case GOTONE | DIGIT: |
1801 | state = GOTTWO; byte = new + (byte << 4); continue; | | 1804 | state = GOTTWO; byte = new + (byte << 4); continue; |
1802 | default: /* | DELIM */ | | 1805 | default: /* | DELIM */ |
1803 | state = VIRGIN; *cp++ = byte; byte = 0; continue; | | 1806 | state = VIRGIN; *cp++ = byte; byte = 0; continue; |
1804 | case GOTONE | END: | | 1807 | case GOTONE | END: |
1805 | case GOTTWO | END: | | 1808 | case GOTTWO | END: |
1806 | *cp++ = byte; /* FALLTHROUGH */ | | 1809 | *cp++ = byte; /* FALLTHROUGH */ |
1807 | case VIRGIN | END: | | 1810 | case VIRGIN | END: |
1808 | break; | | 1811 | break; |
1809 | } | | 1812 | } |
1810 | break; | | 1813 | break; |
1811 | } while (cp < cplim); | | 1814 | } while (cp < cplim); |
1812 | sa->sa_len = cp - (char *)sa; | | 1815 | sa->sa_len = cp - (char *)sa; |
1813 | } | | 1816 | } |