Deleted Added
full compact
route.c (36285) route.c (36832)
1/*
2 * PPP Routing related Module
3 *
4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc. The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
1/*
2 * PPP Routing related Module
3 *
4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc. The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: route.c,v 1.42.2.25 1998/05/16 21:19:00 brian Exp $
20 * $Id: route.c,v 1.45 1998/05/21 21:48:10 brian Exp $
21 *
22 */
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <net/if_types.h>
27#include <net/route.h>
28#include <net/if.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <net/if_dl.h>
32#include <netinet/in_systm.h>
33#include <netinet/ip.h>
34#include <sys/un.h>
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/sysctl.h>
41#include <termios.h>
42
43#include "command.h"
44#include "mbuf.h"
45#include "log.h"
46#include "defs.h"
47#include "iplist.h"
48#include "timer.h"
49#include "throughput.h"
50#include "lqr.h"
51#include "hdlc.h"
52#include "fsm.h"
53#include "lcp.h"
54#include "ccp.h"
55#include "link.h"
56#include "slcompress.h"
57#include "ipcp.h"
58#include "filter.h"
59#include "descriptor.h"
60#include "mp.h"
61#include "bundle.h"
62#include "route.h"
63#include "prompt.h"
64
65static void
66p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
67 struct sockaddr *pmask, int width)
68{
69 char buf[29];
70 struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
71 struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
72 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
73
74 switch (phost->sa_family) {
75 case AF_INET:
76 if (!phost)
77 buf[0] = '\0';
78 else if (ihost->sin_addr.s_addr == INADDR_ANY)
79 strcpy(buf, "default");
80 else if (!mask)
81 strcpy(buf, inet_ntoa(ihost->sin_addr));
82 else {
83 u_int msk = ntohl(mask->sin_addr.s_addr);
84 u_int tst;
85 int bits;
86 int len;
87 struct sockaddr_in net;
88
89 for (tst = 1, bits=32; tst; tst <<= 1, bits--)
90 if (msk & tst)
91 break;
92
93 for (tst <<=1; tst; tst <<= 1)
94 if (!(msk & tst))
95 break;
96
97 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
98 strcpy(buf, inet_ntoa(net.sin_addr));
99 for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
100 if (strcmp(buf+len-2, ".0"))
101 break;
102
103 if (tst) /* non-contiguous :-( */
104 sprintf(buf+strlen(buf),"&0x%08x", msk);
105 else
106 sprintf(buf+strlen(buf), "/%d", bits);
107 }
108 break;
109
110 case AF_LINK:
111 if (dl->sdl_nlen)
112 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
113 else if (dl->sdl_alen) {
114 if (dl->sdl_type == IFT_ETHER) {
115 if (dl->sdl_alen < sizeof buf / 3) {
116 int f;
117 u_char *MAC;
118
119 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
120 for (f = 0; f < dl->sdl_alen; f++)
121 sprintf(buf+f*3, "%02x:", MAC[f]);
122 buf[f*3-1] = '\0';
123 } else
124 strcpy(buf, "??:??:??:??:??:??");
125 } else
126 sprintf(buf, "<IFT type %d>", dl->sdl_type);
127 } else if (dl->sdl_slen)
128 sprintf(buf, "<slen %d?>", dl->sdl_slen);
129 else
130 sprintf(buf, "link#%d", dl->sdl_index);
131 break;
132
133 default:
134 sprintf(buf, "<AF type %d>", phost->sa_family);
135 break;
136 }
137
138 prompt_Printf(prompt, "%-*s ", width-1, buf);
139}
140
141static struct bits {
142 u_long b_mask;
143 char b_val;
144} bits[] = {
145 { RTF_UP, 'U' },
146 { RTF_GATEWAY, 'G' },
147 { RTF_HOST, 'H' },
148 { RTF_REJECT, 'R' },
149 { RTF_DYNAMIC, 'D' },
150 { RTF_MODIFIED, 'M' },
151 { RTF_DONE, 'd' },
152 { RTF_CLONING, 'C' },
153 { RTF_XRESOLVE, 'X' },
154 { RTF_LLINFO, 'L' },
155 { RTF_STATIC, 'S' },
156 { RTF_PROTO1, '1' },
157 { RTF_PROTO2, '2' },
158 { RTF_BLACKHOLE, 'B' },
159#ifdef RTF_WASCLONED
160 { RTF_WASCLONED, 'W' },
161#endif
162#ifdef RTF_PRCLONING
163 { RTF_PRCLONING, 'c' },
164#endif
165#ifdef RTF_PROTO3
166 { RTF_PROTO3, '3' },
167#endif
168#ifdef RTF_BROADCAST
169 { RTF_BROADCAST, 'b' },
170#endif
171 { 0, '\0' }
172};
173
174#ifndef RTF_WASCLONED
175#define RTF_WASCLONED (0)
176#endif
177
178static void
179p_flags(struct prompt *prompt, u_long f, int max)
180{
181 char name[33], *flags;
182 register struct bits *p = bits;
183
184 if (max > sizeof name - 1)
185 max = sizeof name - 1;
186
187 for (flags = name; p->b_mask && flags - name < max; p++)
188 if (p->b_mask & f)
189 *flags++ = p->b_val;
190 *flags = '\0';
191 prompt_Printf(prompt, "%-*.*s", max, max, name);
192}
193
194const char *
195Index2Nam(int idx)
196{
197 static char **ifs;
198 static int nifs, debug_done;
199
200 if (!nifs) {
201 int mib[6], have, had;
202 size_t needed;
203 char *buf, *ptr, *end;
204 struct sockaddr_dl *dl;
205 struct if_msghdr *ifm;
206
207 mib[0] = CTL_NET;
208 mib[1] = PF_ROUTE;
209 mib[2] = 0;
210 mib[3] = 0;
211 mib[4] = NET_RT_IFLIST;
212 mib[5] = 0;
213
214 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
215 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
216 return "???";
217 }
218 if ((buf = malloc(needed)) == NULL)
219 return "???";
220 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
221 free(buf);
222 return "???";
223 }
224 end = buf + needed;
225
226 have = 0;
227 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
228 ifm = (struct if_msghdr *)ptr;
229 dl = (struct sockaddr_dl *)(ifm + 1);
230 if (ifm->ifm_index > 0) {
231 if (ifm->ifm_index > have) {
232 had = have;
233 have = ifm->ifm_index + 5;
234 if (had)
235 ifs = (char **)realloc(ifs, sizeof(char *) * have);
236 else
237 ifs = (char **)malloc(sizeof(char *) * have);
238 if (!ifs) {
239 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
240 nifs = 0;
241 return "???";
242 }
243 memset(ifs + had, '\0', sizeof(char *) * (have - had));
244 }
245 if (ifs[ifm->ifm_index-1] == NULL) {
246 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
247 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
248 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
249 if (nifs < ifm->ifm_index)
250 nifs = ifm->ifm_index;
251 }
252 } else if (log_IsKept(LogDEBUG))
253 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n",
254 ifm->ifm_index);
255 }
256 free(buf);
257 }
258
259 if (log_IsKept(LogDEBUG) && !debug_done) {
260 int f;
261
262 log_Printf(LogDEBUG, "Found the following interfaces:\n");
263 for (f = 0; f < nifs; f++)
264 if (ifs[f] != NULL)
265 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
266 debug_done = 1;
267 }
268
269 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
270 return "???";
271
272 return ifs[idx-1];
273}
274
275int
276route_Show(struct cmdargs const *arg)
277{
278 struct rt_msghdr *rtm;
279 struct sockaddr *sa_dst, *sa_gw, *sa_mask;
280 char *sp, *ep, *cp, *wp;
281 size_t needed;
282 int mib[6];
283
284 mib[0] = CTL_NET;
285 mib[1] = PF_ROUTE;
286 mib[2] = 0;
287 mib[3] = 0;
288 mib[4] = NET_RT_DUMP;
289 mib[5] = 0;
290 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
291 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno));
292 return (1);
293 }
21 *
22 */
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <net/if_types.h>
27#include <net/route.h>
28#include <net/if.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <net/if_dl.h>
32#include <netinet/in_systm.h>
33#include <netinet/ip.h>
34#include <sys/un.h>
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/sysctl.h>
41#include <termios.h>
42
43#include "command.h"
44#include "mbuf.h"
45#include "log.h"
46#include "defs.h"
47#include "iplist.h"
48#include "timer.h"
49#include "throughput.h"
50#include "lqr.h"
51#include "hdlc.h"
52#include "fsm.h"
53#include "lcp.h"
54#include "ccp.h"
55#include "link.h"
56#include "slcompress.h"
57#include "ipcp.h"
58#include "filter.h"
59#include "descriptor.h"
60#include "mp.h"
61#include "bundle.h"
62#include "route.h"
63#include "prompt.h"
64
65static void
66p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
67 struct sockaddr *pmask, int width)
68{
69 char buf[29];
70 struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
71 struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
72 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
73
74 switch (phost->sa_family) {
75 case AF_INET:
76 if (!phost)
77 buf[0] = '\0';
78 else if (ihost->sin_addr.s_addr == INADDR_ANY)
79 strcpy(buf, "default");
80 else if (!mask)
81 strcpy(buf, inet_ntoa(ihost->sin_addr));
82 else {
83 u_int msk = ntohl(mask->sin_addr.s_addr);
84 u_int tst;
85 int bits;
86 int len;
87 struct sockaddr_in net;
88
89 for (tst = 1, bits=32; tst; tst <<= 1, bits--)
90 if (msk & tst)
91 break;
92
93 for (tst <<=1; tst; tst <<= 1)
94 if (!(msk & tst))
95 break;
96
97 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
98 strcpy(buf, inet_ntoa(net.sin_addr));
99 for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
100 if (strcmp(buf+len-2, ".0"))
101 break;
102
103 if (tst) /* non-contiguous :-( */
104 sprintf(buf+strlen(buf),"&0x%08x", msk);
105 else
106 sprintf(buf+strlen(buf), "/%d", bits);
107 }
108 break;
109
110 case AF_LINK:
111 if (dl->sdl_nlen)
112 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
113 else if (dl->sdl_alen) {
114 if (dl->sdl_type == IFT_ETHER) {
115 if (dl->sdl_alen < sizeof buf / 3) {
116 int f;
117 u_char *MAC;
118
119 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
120 for (f = 0; f < dl->sdl_alen; f++)
121 sprintf(buf+f*3, "%02x:", MAC[f]);
122 buf[f*3-1] = '\0';
123 } else
124 strcpy(buf, "??:??:??:??:??:??");
125 } else
126 sprintf(buf, "<IFT type %d>", dl->sdl_type);
127 } else if (dl->sdl_slen)
128 sprintf(buf, "<slen %d?>", dl->sdl_slen);
129 else
130 sprintf(buf, "link#%d", dl->sdl_index);
131 break;
132
133 default:
134 sprintf(buf, "<AF type %d>", phost->sa_family);
135 break;
136 }
137
138 prompt_Printf(prompt, "%-*s ", width-1, buf);
139}
140
141static struct bits {
142 u_long b_mask;
143 char b_val;
144} bits[] = {
145 { RTF_UP, 'U' },
146 { RTF_GATEWAY, 'G' },
147 { RTF_HOST, 'H' },
148 { RTF_REJECT, 'R' },
149 { RTF_DYNAMIC, 'D' },
150 { RTF_MODIFIED, 'M' },
151 { RTF_DONE, 'd' },
152 { RTF_CLONING, 'C' },
153 { RTF_XRESOLVE, 'X' },
154 { RTF_LLINFO, 'L' },
155 { RTF_STATIC, 'S' },
156 { RTF_PROTO1, '1' },
157 { RTF_PROTO2, '2' },
158 { RTF_BLACKHOLE, 'B' },
159#ifdef RTF_WASCLONED
160 { RTF_WASCLONED, 'W' },
161#endif
162#ifdef RTF_PRCLONING
163 { RTF_PRCLONING, 'c' },
164#endif
165#ifdef RTF_PROTO3
166 { RTF_PROTO3, '3' },
167#endif
168#ifdef RTF_BROADCAST
169 { RTF_BROADCAST, 'b' },
170#endif
171 { 0, '\0' }
172};
173
174#ifndef RTF_WASCLONED
175#define RTF_WASCLONED (0)
176#endif
177
178static void
179p_flags(struct prompt *prompt, u_long f, int max)
180{
181 char name[33], *flags;
182 register struct bits *p = bits;
183
184 if (max > sizeof name - 1)
185 max = sizeof name - 1;
186
187 for (flags = name; p->b_mask && flags - name < max; p++)
188 if (p->b_mask & f)
189 *flags++ = p->b_val;
190 *flags = '\0';
191 prompt_Printf(prompt, "%-*.*s", max, max, name);
192}
193
194const char *
195Index2Nam(int idx)
196{
197 static char **ifs;
198 static int nifs, debug_done;
199
200 if (!nifs) {
201 int mib[6], have, had;
202 size_t needed;
203 char *buf, *ptr, *end;
204 struct sockaddr_dl *dl;
205 struct if_msghdr *ifm;
206
207 mib[0] = CTL_NET;
208 mib[1] = PF_ROUTE;
209 mib[2] = 0;
210 mib[3] = 0;
211 mib[4] = NET_RT_IFLIST;
212 mib[5] = 0;
213
214 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
215 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
216 return "???";
217 }
218 if ((buf = malloc(needed)) == NULL)
219 return "???";
220 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
221 free(buf);
222 return "???";
223 }
224 end = buf + needed;
225
226 have = 0;
227 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
228 ifm = (struct if_msghdr *)ptr;
229 dl = (struct sockaddr_dl *)(ifm + 1);
230 if (ifm->ifm_index > 0) {
231 if (ifm->ifm_index > have) {
232 had = have;
233 have = ifm->ifm_index + 5;
234 if (had)
235 ifs = (char **)realloc(ifs, sizeof(char *) * have);
236 else
237 ifs = (char **)malloc(sizeof(char *) * have);
238 if (!ifs) {
239 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
240 nifs = 0;
241 return "???";
242 }
243 memset(ifs + had, '\0', sizeof(char *) * (have - had));
244 }
245 if (ifs[ifm->ifm_index-1] == NULL) {
246 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
247 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
248 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
249 if (nifs < ifm->ifm_index)
250 nifs = ifm->ifm_index;
251 }
252 } else if (log_IsKept(LogDEBUG))
253 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n",
254 ifm->ifm_index);
255 }
256 free(buf);
257 }
258
259 if (log_IsKept(LogDEBUG) && !debug_done) {
260 int f;
261
262 log_Printf(LogDEBUG, "Found the following interfaces:\n");
263 for (f = 0; f < nifs; f++)
264 if (ifs[f] != NULL)
265 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
266 debug_done = 1;
267 }
268
269 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
270 return "???";
271
272 return ifs[idx-1];
273}
274
275int
276route_Show(struct cmdargs const *arg)
277{
278 struct rt_msghdr *rtm;
279 struct sockaddr *sa_dst, *sa_gw, *sa_mask;
280 char *sp, *ep, *cp, *wp;
281 size_t needed;
282 int mib[6];
283
284 mib[0] = CTL_NET;
285 mib[1] = PF_ROUTE;
286 mib[2] = 0;
287 mib[3] = 0;
288 mib[4] = NET_RT_DUMP;
289 mib[5] = 0;
290 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
291 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno));
292 return (1);
293 }
294 if (needed < 0)
295 return (1);
296 sp = malloc(needed);
297 if (sp == NULL)
298 return (1);
299 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
300 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno));
301 free(sp);
302 return (1);
303 }
304 ep = sp + needed;
305
306 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n",
307 "Destination", "Gateway");
308 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
309 rtm = (struct rt_msghdr *) cp;
310 wp = (char *)(rtm+1);
311
312 if (rtm->rtm_addrs & RTA_DST) {
313 sa_dst = (struct sockaddr *)wp;
314 wp += sa_dst->sa_len;
315 } else
316 sa_dst = NULL;
317
318 if (rtm->rtm_addrs & RTA_GATEWAY) {
319 sa_gw = (struct sockaddr *)wp;
320 wp += sa_gw->sa_len;
321 } else
322 sa_gw = NULL;
323
324 if (rtm->rtm_addrs & RTA_NETMASK) {
325 sa_mask = (struct sockaddr *)wp;
326 wp += sa_mask->sa_len;
327 } else
328 sa_mask = NULL;
329
330 p_sockaddr(arg->prompt, sa_dst, sa_mask, 20);
331 p_sockaddr(arg->prompt, sa_gw, NULL, 20);
332
333 p_flags(arg->prompt, rtm->rtm_flags, 6);
334 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index));
335 }
336 free(sp);
337 return 0;
338}
339
340/*
341 * Delete routes associated with our interface
342 */
343void
344route_IfDelete(struct bundle *bundle, int all)
345{
346 struct rt_msghdr *rtm;
347 struct sockaddr *sa;
348 struct in_addr sa_dst, sa_none;
349 int pass;
350 size_t needed;
351 char *sp, *cp, *ep;
352 int mib[6];
353
354 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->ifp.Index);
355 sa_none.s_addr = INADDR_ANY;
356
357 mib[0] = CTL_NET;
358 mib[1] = PF_ROUTE;
359 mib[2] = 0;
360 mib[3] = 0;
361 mib[4] = NET_RT_DUMP;
362 mib[5] = 0;
363 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
364 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n",
365 strerror(errno));
366 return;
367 }
294 sp = malloc(needed);
295 if (sp == NULL)
296 return (1);
297 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
298 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno));
299 free(sp);
300 return (1);
301 }
302 ep = sp + needed;
303
304 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n",
305 "Destination", "Gateway");
306 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
307 rtm = (struct rt_msghdr *) cp;
308 wp = (char *)(rtm+1);
309
310 if (rtm->rtm_addrs & RTA_DST) {
311 sa_dst = (struct sockaddr *)wp;
312 wp += sa_dst->sa_len;
313 } else
314 sa_dst = NULL;
315
316 if (rtm->rtm_addrs & RTA_GATEWAY) {
317 sa_gw = (struct sockaddr *)wp;
318 wp += sa_gw->sa_len;
319 } else
320 sa_gw = NULL;
321
322 if (rtm->rtm_addrs & RTA_NETMASK) {
323 sa_mask = (struct sockaddr *)wp;
324 wp += sa_mask->sa_len;
325 } else
326 sa_mask = NULL;
327
328 p_sockaddr(arg->prompt, sa_dst, sa_mask, 20);
329 p_sockaddr(arg->prompt, sa_gw, NULL, 20);
330
331 p_flags(arg->prompt, rtm->rtm_flags, 6);
332 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index));
333 }
334 free(sp);
335 return 0;
336}
337
338/*
339 * Delete routes associated with our interface
340 */
341void
342route_IfDelete(struct bundle *bundle, int all)
343{
344 struct rt_msghdr *rtm;
345 struct sockaddr *sa;
346 struct in_addr sa_dst, sa_none;
347 int pass;
348 size_t needed;
349 char *sp, *cp, *ep;
350 int mib[6];
351
352 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->ifp.Index);
353 sa_none.s_addr = INADDR_ANY;
354
355 mib[0] = CTL_NET;
356 mib[1] = PF_ROUTE;
357 mib[2] = 0;
358 mib[3] = 0;
359 mib[4] = NET_RT_DUMP;
360 mib[5] = 0;
361 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
362 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n",
363 strerror(errno));
364 return;
365 }
368 if (needed < 0)
369 return;
370
371 sp = malloc(needed);
372 if (sp == NULL)
373 return;
374
375 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
376 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n",
377 strerror(errno));
378 free(sp);
379 return;
380 }
381 ep = sp + needed;
382
383 for (pass = 0; pass < 2; pass++) {
384 /*
385 * We do 2 passes. The first deletes all cloned routes. The second
386 * deletes all non-cloned routes. This is necessary to avoid
387 * potential errors from trying to delete route X after route Y where
388 * route X was cloned from route Y (and is no longer there 'cos it
389 * may have gone with route Y).
390 */
391 if (RTF_WASCLONED == 0 && pass == 0)
392 /* So we can't tell ! */
393 continue;
394 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
395 rtm = (struct rt_msghdr *) cp;
396 sa = (struct sockaddr *) (rtm + 1);
397 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s),"
398 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
399 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
400 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
401 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
402 rtm->rtm_index == bundle->ifp.Index &&
403 (all || (rtm->rtm_flags & RTF_GATEWAY))) {
404 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
405 sa = (struct sockaddr *)((char *)sa + sa->sa_len);
406 if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
407 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
408 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
409 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass);
410 bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0);
411 } else
412 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
413 } else
414 log_Printf(LogDEBUG,
415 "route_IfDelete: Can't remove routes of %d family !\n",
416 sa->sa_family);
417 }
418 }
419 }
420 free(sp);
421}
422
423int
424GetIfIndex(char *name)
425{
426 int idx;
427 const char *got;
428
429 idx = 1;
430 while (strcmp(got = Index2Nam(idx), "???"))
431 if (!strcmp(got, name))
432 return idx;
433 else
434 idx++;
435 return -1;
436}
437
438void
439route_Change(struct bundle *bundle, struct sticky_route *r,
440 struct in_addr me, struct in_addr peer)
441{
442 struct in_addr none, del;
443
444 none.s_addr = INADDR_ANY;
445 for (; r; r = r->next) {
446 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) {
447 del.s_addr = r->dst.s_addr & r->mask.s_addr;
448 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
449 r->dst = me;
450 if (r->type & ROUTE_GWHISADDR)
451 r->gw = peer;
452 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) {
453 del.s_addr = r->dst.s_addr & r->mask.s_addr;
454 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
455 r->dst = peer;
456 if (r->type & ROUTE_GWHISADDR)
457 r->gw = peer;
458 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr)
459 r->gw = peer;
460 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1);
461 }
462}
463
464void
465route_Clean(struct bundle *bundle, struct sticky_route *r)
466{
467 struct in_addr none, del;
468
469 none.s_addr = INADDR_ANY;
470 for (; r; r = r->next) {
471 del.s_addr = r->dst.s_addr & r->mask.s_addr;
472 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
473 }
474}
475
476void
477route_Add(struct sticky_route **rp, int type, struct in_addr dst,
478 struct in_addr mask, struct in_addr gw)
479{
480 if (type != ROUTE_STATIC) {
481 struct sticky_route *r;
482 int dsttype = type & ROUTE_DSTANY;
483
484 r = NULL;
485 while (*rp) {
486 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
487 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) {
488 r = *rp;
489 *rp = r->next;
490 } else
491 rp = &(*rp)->next;
492 }
493
494 if (!r)
495 r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
496 r->type = type;
497 r->next = NULL;
498 r->dst = dst;
499 r->mask = mask;
500 r->gw = gw;
501 *rp = r;
502 }
503}
504
505void
506route_Delete(struct sticky_route **rp, int type, struct in_addr dst)
507{
508 struct sticky_route *r;
509 int dsttype = type & ROUTE_DSTANY;
510
511 for (; *rp; rp = &(*rp)->next) {
512 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
513 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) {
514 r = *rp;
515 *rp = r->next;
516 free(r);
517 break;
518 }
519 }
520}
521
522void
523route_DeleteAll(struct sticky_route **rp)
524{
525 struct sticky_route *r, *rn;
526
527 for (r = *rp; r; r = rn) {
528 rn = r->next;
529 free(r);
530 }
531 *rp = NULL;
532}
533
534void
535route_ShowSticky(struct prompt *p, struct sticky_route *r)
536{
537 int def;
538
539 prompt_Printf(p, "Sticky routes:\n");
540 for (; r; r = r->next) {
541 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY;
542
543 prompt_Printf(p, " add ");
544 if (r->type & ROUTE_DSTMYADDR)
545 prompt_Printf(p, "MYADDR");
546 else if (r->type & ROUTE_DSTHISADDR)
547 prompt_Printf(p, "HISADDR");
548 else if (!def)
549 prompt_Printf(p, "%s", inet_ntoa(r->dst));
550
551 if (def)
552 prompt_Printf(p, "default ");
553 else
554 prompt_Printf(p, " %s ", inet_ntoa(r->mask));
555
556 if (r->type & ROUTE_GWHISADDR)
557 prompt_Printf(p, "HISADDR\n");
558 else
559 prompt_Printf(p, "%s\n", inet_ntoa(r->gw));
560 }
561}
366
367 sp = malloc(needed);
368 if (sp == NULL)
369 return;
370
371 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
372 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n",
373 strerror(errno));
374 free(sp);
375 return;
376 }
377 ep = sp + needed;
378
379 for (pass = 0; pass < 2; pass++) {
380 /*
381 * We do 2 passes. The first deletes all cloned routes. The second
382 * deletes all non-cloned routes. This is necessary to avoid
383 * potential errors from trying to delete route X after route Y where
384 * route X was cloned from route Y (and is no longer there 'cos it
385 * may have gone with route Y).
386 */
387 if (RTF_WASCLONED == 0 && pass == 0)
388 /* So we can't tell ! */
389 continue;
390 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
391 rtm = (struct rt_msghdr *) cp;
392 sa = (struct sockaddr *) (rtm + 1);
393 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s),"
394 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
395 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
396 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
397 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
398 rtm->rtm_index == bundle->ifp.Index &&
399 (all || (rtm->rtm_flags & RTF_GATEWAY))) {
400 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
401 sa = (struct sockaddr *)((char *)sa + sa->sa_len);
402 if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
403 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
404 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
405 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass);
406 bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0);
407 } else
408 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
409 } else
410 log_Printf(LogDEBUG,
411 "route_IfDelete: Can't remove routes of %d family !\n",
412 sa->sa_family);
413 }
414 }
415 }
416 free(sp);
417}
418
419int
420GetIfIndex(char *name)
421{
422 int idx;
423 const char *got;
424
425 idx = 1;
426 while (strcmp(got = Index2Nam(idx), "???"))
427 if (!strcmp(got, name))
428 return idx;
429 else
430 idx++;
431 return -1;
432}
433
434void
435route_Change(struct bundle *bundle, struct sticky_route *r,
436 struct in_addr me, struct in_addr peer)
437{
438 struct in_addr none, del;
439
440 none.s_addr = INADDR_ANY;
441 for (; r; r = r->next) {
442 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) {
443 del.s_addr = r->dst.s_addr & r->mask.s_addr;
444 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
445 r->dst = me;
446 if (r->type & ROUTE_GWHISADDR)
447 r->gw = peer;
448 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) {
449 del.s_addr = r->dst.s_addr & r->mask.s_addr;
450 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
451 r->dst = peer;
452 if (r->type & ROUTE_GWHISADDR)
453 r->gw = peer;
454 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr)
455 r->gw = peer;
456 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1);
457 }
458}
459
460void
461route_Clean(struct bundle *bundle, struct sticky_route *r)
462{
463 struct in_addr none, del;
464
465 none.s_addr = INADDR_ANY;
466 for (; r; r = r->next) {
467 del.s_addr = r->dst.s_addr & r->mask.s_addr;
468 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
469 }
470}
471
472void
473route_Add(struct sticky_route **rp, int type, struct in_addr dst,
474 struct in_addr mask, struct in_addr gw)
475{
476 if (type != ROUTE_STATIC) {
477 struct sticky_route *r;
478 int dsttype = type & ROUTE_DSTANY;
479
480 r = NULL;
481 while (*rp) {
482 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
483 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) {
484 r = *rp;
485 *rp = r->next;
486 } else
487 rp = &(*rp)->next;
488 }
489
490 if (!r)
491 r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
492 r->type = type;
493 r->next = NULL;
494 r->dst = dst;
495 r->mask = mask;
496 r->gw = gw;
497 *rp = r;
498 }
499}
500
501void
502route_Delete(struct sticky_route **rp, int type, struct in_addr dst)
503{
504 struct sticky_route *r;
505 int dsttype = type & ROUTE_DSTANY;
506
507 for (; *rp; rp = &(*rp)->next) {
508 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
509 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) {
510 r = *rp;
511 *rp = r->next;
512 free(r);
513 break;
514 }
515 }
516}
517
518void
519route_DeleteAll(struct sticky_route **rp)
520{
521 struct sticky_route *r, *rn;
522
523 for (r = *rp; r; r = rn) {
524 rn = r->next;
525 free(r);
526 }
527 *rp = NULL;
528}
529
530void
531route_ShowSticky(struct prompt *p, struct sticky_route *r)
532{
533 int def;
534
535 prompt_Printf(p, "Sticky routes:\n");
536 for (; r; r = r->next) {
537 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY;
538
539 prompt_Printf(p, " add ");
540 if (r->type & ROUTE_DSTMYADDR)
541 prompt_Printf(p, "MYADDR");
542 else if (r->type & ROUTE_DSTHISADDR)
543 prompt_Printf(p, "HISADDR");
544 else if (!def)
545 prompt_Printf(p, "%s", inet_ntoa(r->dst));
546
547 if (def)
548 prompt_Printf(p, "default ");
549 else
550 prompt_Printf(p, " %s ", inet_ntoa(r->mask));
551
552 if (r->type & ROUTE_GWHISADDR)
553 prompt_Printf(p, "HISADDR\n");
554 else
555 prompt_Printf(p, "%s\n", inet_ntoa(r->gw));
556 }
557}