1/* route 2 * 3 * Similar to the standard Unix route, but with only the necessary 4 * parts for AF_INET 5 * 6 * Bjorn Wesen, Axis Communications AB 7 * 8 * Author of the original route: 9 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> 10 * (derived from FvK's 'route.c 1.70 01/04/94') 11 * 12 * This program is free software; you can redistribute it 13 * and/or modify it under the terms of the GNU General 14 * Public License as published by the Free Software 15 * Foundation; either version 2 of the License, or (at 16 * your option) any later version. 17 * 18 * $Id: route.c,v 1.1.1.1 2008/10/15 03:28:33 james26_jang Exp $ 19 * 20 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> 21 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> 22 */ 23 24#include <sys/types.h> 25#include <sys/ioctl.h> 26#include <sys/socket.h> 27#include <net/route.h> 28#include <linux/param.h> // HZ 29#include <netinet/in.h> 30#include <arpa/inet.h> 31#include <stdio.h> 32#include <errno.h> 33#include <fcntl.h> 34#include <stdlib.h> 35#include <string.h> 36#include <getopt.h> 37#include <unistd.h> 38#include <ctype.h> 39#include "busybox.h" 40 41#define _(x) x 42 43#define RTACTION_ADD 1 44#define RTACTION_DEL 2 45#define RTACTION_HELP 3 46#define RTACTION_FLUSH 4 47#define RTACTION_SHOW 5 48 49#define E_NOTFOUND 8 50#define E_SOCK 7 51#define E_LOOKUP 6 52#define E_VERSION 5 53#define E_USAGE 4 54#define E_OPTERR 3 55#define E_INTERN 2 56#define E_NOSUPP 1 57 58 59static int 60INET_resolve(char *name, struct sockaddr *sa) 61{ 62 struct sockaddr_in *s_in = (struct sockaddr_in *)sa; 63 64 s_in->sin_family = AF_INET; 65 s_in->sin_port = 0; 66 67 /* Default is special, meaning 0.0.0.0. */ 68 if (strcmp(name, "default")==0) { 69 s_in->sin_addr.s_addr = INADDR_ANY; 70 return 1; 71 } 72 /* Look to see if it's a dotted quad. */ 73 if (inet_aton(name, &s_in->sin_addr)) { 74 return 0; 75 } 76 /* guess not.. */ 77 return -1; 78} 79 80#if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */ 81#define HAVE_NEW_ADDRT 1 82#endif 83#ifdef RTF_IRTT /* route */ 84#define HAVE_RTF_IRTT 1 85#endif 86#ifdef RTF_REJECT /* route */ 87#define HAVE_RTF_REJECT 1 88#endif 89 90#if HAVE_NEW_ADDRT 91#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr) 92#define full_mask(x) (x) 93#else 94#define mask_in_addr(x) ((x).rt_genmask) 95#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr) 96#endif 97 98/* add or delete a route depending on action */ 99 100static int 101INET_setroute(int action, int options, char **args) 102{ 103 struct rtentry rt; 104 char target[128], gateway[128] = "NONE", netmask[128] = "default"; 105 int xflag, isnet; 106 int skfd; 107 108 xflag = 0; 109 110 if (strcmp(*args, "-net")==0) { 111 xflag = 1; 112 args++; 113 } else if (strcmp(*args, "-host")==0) { 114 xflag = 2; 115 args++; 116 } 117 if (*args == NULL) 118 show_usage(); 119 120 safe_strncpy(target, *args++, (sizeof target)); 121 122 /* Clean out the RTREQ structure. */ 123 memset((char *) &rt, 0, sizeof(struct rtentry)); 124 125 126 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) { 127 error_msg(_("can't resolve %s"), target); 128 return EXIT_FAILURE; 129 } 130 131 switch (xflag) { 132 case 1: 133 isnet = 1; 134 break; 135 136 case 2: 137 isnet = 0; 138 break; 139 140 default: 141 break; 142 } 143 144 /* Fill in the other fields. */ 145 rt.rt_flags = (RTF_UP | RTF_HOST); 146 if (isnet) 147 rt.rt_flags &= ~RTF_HOST; 148 149 while (*args) { 150 if (strcmp(*args, "metric")==0) { 151 int metric; 152 153 args++; 154 if (!*args || !isdigit(**args)) 155 show_usage(); 156 metric = atoi(*args); 157#if HAVE_NEW_ADDRT 158 rt.rt_metric = metric + 1; 159#else 160 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); 161#endif 162 args++; 163 continue; 164 } 165 166 if (strcmp(*args, "netmask")==0) { 167 struct sockaddr mask; 168 169 args++; 170 if (!*args || mask_in_addr(rt)) 171 show_usage(); 172 safe_strncpy(netmask, *args, (sizeof netmask)); 173 if ((isnet = INET_resolve(netmask, &mask)) < 0) { 174 error_msg(_("can't resolve netmask %s"), netmask); 175 return E_LOOKUP; 176 } 177 rt.rt_genmask = full_mask(mask); 178 args++; 179 continue; 180 } 181 182 if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { 183 args++; 184 if (!*args) 185 show_usage(); 186 if (rt.rt_flags & RTF_GATEWAY) 187 show_usage(); 188 safe_strncpy(gateway, *args, (sizeof gateway)); 189 if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { 190 error_msg(_("can't resolve gw %s"), gateway); 191 return E_LOOKUP; 192 } 193 if (isnet) { 194 error_msg( 195 _("%s: cannot use a NETWORK as gateway!"), 196 gateway); 197 return E_OPTERR; 198 } 199 rt.rt_flags |= RTF_GATEWAY; 200 args++; 201 continue; 202 } 203 204 if (strcmp(*args, "mss")==0) { 205 args++; 206 rt.rt_flags |= RTF_MSS; 207 if (!*args) 208 show_usage(); 209 rt.rt_mss = atoi(*args); 210 args++; 211 if (rt.rt_mss < 64 || rt.rt_mss > 32768) { 212 error_msg(_("Invalid MSS.")); 213 return E_OPTERR; 214 } 215 continue; 216 } 217 218 if (strcmp(*args, "window")==0) { 219 args++; 220 if (!*args) 221 show_usage(); 222 rt.rt_flags |= RTF_WINDOW; 223 rt.rt_window = atoi(*args); 224 args++; 225 if (rt.rt_window < 128) { 226 error_msg(_("Invalid window.")); 227 return E_OPTERR; 228 } 229 continue; 230 } 231 232 if (strcmp(*args, "irtt")==0) { 233 args++; 234 if (!*args) 235 show_usage(); 236 args++; 237#if HAVE_RTF_IRTT 238 rt.rt_flags |= RTF_IRTT; 239 rt.rt_irtt = atoi(*(args - 1)); 240 rt.rt_irtt *= (HZ / 100); 241#else 242 ENOSUPP("inet_setroute", "RTF_IRTT"); 243#endif 244 continue; 245 } 246 247 if (strcmp(*args, "reject")==0) { 248 args++; 249#if HAVE_RTF_REJECT 250 rt.rt_flags |= RTF_REJECT; 251#else 252 ENOSUPP("inet_setroute", "RTF_REJECT"); 253#endif 254 continue; 255 } 256 if (strcmp(*args, "mod")==0) { 257 args++; 258 rt.rt_flags |= RTF_MODIFIED; 259 continue; 260 } 261 if (strcmp(*args, "dyn")==0) { 262 args++; 263 rt.rt_flags |= RTF_DYNAMIC; 264 continue; 265 } 266 if (strcmp(*args, "reinstate")==0) { 267 args++; 268 rt.rt_flags |= RTF_REINSTATE; 269 continue; 270 } 271 if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { 272 args++; 273 if (rt.rt_dev || *args == NULL) 274 show_usage(); 275 rt.rt_dev = *args++; 276 continue; 277 } 278 /* nothing matches */ 279 if (!rt.rt_dev) { 280 rt.rt_dev = *args++; 281 if (*args) 282 show_usage(); /* must be last to catch typos */ 283 } else { 284 show_usage(); 285 } 286 } 287 288#if HAVE_RTF_REJECT 289 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) 290 rt.rt_dev = "lo"; 291#endif 292 293 /* sanity checks.. */ 294 if (mask_in_addr(rt)) { 295 unsigned long mask = mask_in_addr(rt); 296 mask = ~ntohl(mask); 297 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { 298 error_msg( 299 _("netmask %.8x doesn't make sense with host route"), 300 (unsigned int)mask); 301 return E_OPTERR; 302 } 303 if (mask & (mask + 1)) { 304 error_msg(_("bogus netmask %s"), netmask); 305 return E_OPTERR; 306 } 307 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; 308 if (mask & ~mask_in_addr(rt)) { 309 error_msg(_("netmask doesn't match route address")); 310 return E_OPTERR; 311 } 312 } 313 /* Fill out netmask if still unset */ 314 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) 315 mask_in_addr(rt) = 0xffffffff; 316 317 /* Create a socket to the INET kernel. */ 318 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 319 perror("socket"); 320 return E_SOCK; 321 } 322 /* Tell the kernel to accept this route. */ 323 if (action == RTACTION_DEL) { 324 if (ioctl(skfd, SIOCDELRT, &rt) < 0) { 325 perror("SIOCDELRT"); 326 close(skfd); 327 return E_SOCK; 328 } 329 } else { 330 if (ioctl(skfd, SIOCADDRT, &rt) < 0) { 331 perror("SIOCADDRT"); 332 close(skfd); 333 return E_SOCK; 334 } 335 } 336 337 /* Close the socket. */ 338 (void) close(skfd); 339 return EXIT_SUCCESS; 340} 341 342static void displayroutes(void) 343{ 344 char buff[256]; 345 int nl = 0 ; 346 struct in_addr dest; 347 struct in_addr gw; 348 struct in_addr mask; 349 int flgs, ref, use, metric; 350 char flags[4]; 351 unsigned long int d,g,m; 352 353 char sdest[16], sgw[16]; 354 355 356 FILE *fp = xfopen("/proc/net/route", "r"); 357 358 while( fgets(buff, sizeof(buff), fp) != NULL ) { 359 if(nl) { 360 int ifl = 0; 361 while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0') 362 ifl++; 363 buff[ifl]=0; /* interface */ 364 if(sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx", 365 &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { 366 error_msg_and_die( "Unsuported kernel route format\n"); 367 } 368 if(nl==1) { 369 printf("Kernel IP routing table\n" 370"Destination Gateway Genmask Flags Metric Ref Use Iface\n"); 371 } 372 373 374 ifl = 0; /* parse flags */ 375 if(flgs&1) 376 flags[ifl++]='U'; 377 if(flgs&2) 378 flags[ifl++]='G'; 379 if(flgs&4) 380 flags[ifl++]='H'; 381 flags[ifl]=0; 382 dest.s_addr = d; 383 gw.s_addr = g; 384 mask.s_addr = m; 385 strcpy(sdest, (dest.s_addr==0 ? "default" : 386 inet_ntoa(dest))); 387 strcpy(sgw, (gw.s_addr==0 ? "*" : 388 inet_ntoa(gw))); 389 printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", 390 sdest, sgw, 391 inet_ntoa(mask), 392 flags, metric, ref, use, buff); 393 } 394 nl++; 395 } 396} 397 398int route_main(int argc, char **argv) 399{ 400 int what = 0; 401 402 argc--; 403 argv++; 404 405 if (*argv == NULL) { 406 displayroutes(); 407 return EXIT_SUCCESS; 408 } else { 409 /* check verb */ 410 if (strcmp(*argv, "add")==0) 411 what = RTACTION_ADD; 412 else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) 413 what = RTACTION_DEL; 414 else if (strcmp(*argv, "flush")==0) 415 what = RTACTION_FLUSH; 416 else 417 show_usage(); 418 } 419 420 return INET_setroute(what, 0, ++argv); 421} 422