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