route.c revision 31048
11984Scsgr/* 24246Sphk * PPP Routing related Module 34246Sphk * 44246Sphk * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 54246Sphk * 64246Sphk * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 74246Sphk * 81984Scsgr * Redistribution and use in source and binary forms are permitted 917141Sjkh * provided that the above copyright notice and this paragraph are 101984Scsgr * duplicated in all such forms and that any documentation, 111984Scsgr * advertising materials, and other materials related to such 121984Scsgr * distribution and use acknowledge that the software was developed 131984Scsgr * by the Internet Initiative Japan, Inc. The name of the 1417141Sjkh * IIJ may not be used to endorse or promote products derived 151984Scsgr * from this software without specific prior written permission. 161984Scsgr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171984Scsgr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181984Scsgr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1917141Sjkh * 204246Sphk * $Id: route.c,v 1.21 1997/11/08 00:28:11 brian Exp $ 211984Scsgr * 224246Sphk */ 234246Sphk 244246Sphk#include <sys/param.h> 254246Sphk#include <sys/time.h> 264246Sphk#include <sys/socket.h> 274246Sphk#include <net/route.h> 284246Sphk#include <net/if.h> 294246Sphk#include <netinet/in_systm.h> 304246Sphk#include <netinet/in.h> 314246Sphk#include <arpa/inet.h> 324246Sphk 334246Sphk#include <errno.h> 344246Sphk#include <machine/endian.h> 354246Sphk#include <stdio.h> 364246Sphk#include <stdlib.h> 371984Scsgr#include <string.h> 381984Scsgr#include <sys/ioctl.h> 398870Srgrimes#include <sys/sysctl.h> 404246Sphk#include <unistd.h> 411984Scsgr 421984Scsgr#include "mbuf.h" 431984Scsgr#include "log.h" 441984Scsgr#include "loadalias.h" 451984Scsgr#include "command.h" 461984Scsgr#include "vars.h" 471984Scsgr#include "route.h" 484246Sphk 494246Sphkstatic int IfIndex; 504246Sphk 514246Sphkstruct rtmsg { 524246Sphk struct rt_msghdr m_rtm; 534246Sphk char m_space[64]; 544246Sphk}; 554246Sphk 564246Sphkstatic int seqno; 574246Sphk 584246Sphkvoid 594246SphkOsSetRoute(int cmd, 601984Scsgr struct in_addr dst, 614246Sphk struct in_addr gateway, 624246Sphk struct in_addr mask) 631984Scsgr{ 644246Sphk struct rtmsg rtmes; 654246Sphk int s, nb, wb; 664246Sphk char *cp; 671984Scsgr u_long *lp; 684246Sphk struct sockaddr_in rtdata; 694246Sphk 704246Sphk s = socket(PF_ROUTE, SOCK_RAW, 0); 714246Sphk if (s < 0) { 724246Sphk LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 734246Sphk return; 744246Sphk } 754246Sphk memset(&rtmes, '\0', sizeof(rtmes)); 764246Sphk rtmes.m_rtm.rtm_version = RTM_VERSION; 774246Sphk rtmes.m_rtm.rtm_type = cmd; 784246Sphk rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 794246Sphk rtmes.m_rtm.rtm_seq = ++seqno; 804246Sphk rtmes.m_rtm.rtm_pid = getpid(); 814246Sphk rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 824246Sphk 834246Sphk memset(&rtdata, '\0', sizeof(rtdata)); 844246Sphk rtdata.sin_len = 16; 854246Sphk rtdata.sin_family = AF_INET; 864246Sphk rtdata.sin_port = 0; 874246Sphk rtdata.sin_addr = dst; 884246Sphk 894246Sphk cp = rtmes.m_space; 904246Sphk memcpy(cp, &rtdata, 16); 914246Sphk cp += 16; 928870Srgrimes if (gateway.s_addr) { 934246Sphk rtdata.sin_addr = gateway; 944246Sphk memcpy(cp, &rtdata, 16); 954246Sphk cp += 16; 964246Sphk rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 974246Sphk } 984246Sphk if (dst.s_addr == INADDR_ANY) 994246Sphk mask.s_addr = INADDR_ANY; 1004246Sphk 1014246Sphk lp = (u_long *) cp; 1021984Scsgr 1034246Sphk if (mask.s_addr) { 1041984Scsgr *lp++ = 8; 1054246Sphk cp += sizeof(int); 1064246Sphk *lp = mask.s_addr; 1074246Sphk } else 1084246Sphk *lp = 0; 1091984Scsgr cp += sizeof(u_long); 1104246Sphk 1114246Sphk nb = cp - (char *) &rtmes; 1128870Srgrimes rtmes.m_rtm.rtm_msglen = nb; 1138870Srgrimes wb = write(s, &rtmes, nb); 1144246Sphk if (wb < 0) { 1154246Sphk LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 1164246Sphk LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 1174246Sphk LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 1184246Sphk switch (rtmes.m_rtm.rtm_errno) { 1194246Sphk case EEXIST: 1204246Sphk LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 1211984Scsgr break; 1224246Sphk case ESRCH: 1231984Scsgr LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 1244246Sphk break; 1254246Sphk case ENOBUFS: 1261984Scsgr default: 1274246Sphk LogPrintf(LogTCPIP, "Add/Del route failed: %s\n", 1284246Sphk strerror(rtmes.m_rtm.rtm_errno)); 1294246Sphk break; 1304246Sphk } 1314246Sphk } 1324246Sphk LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb, 1334246Sphk dst.s_addr, gateway.s_addr); 1344246Sphk close(s); 1351984Scsgr} 1361984Scsgr 1374246Sphkstatic void 1388870Srgrimesp_sockaddr(struct sockaddr * sa, int width) 1394246Sphk{ 1404246Sphk if (VarTerm) { 1414246Sphk register char *cp; 1424246Sphk register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa; 1434246Sphk 1444246Sphk cp = (sock_in->sin_addr.s_addr == 0) ? "default" : 1454246Sphk inet_ntoa(sock_in->sin_addr); 1464246Sphk fprintf(VarTerm, "%-*.*s ", width, width, cp); 1474246Sphk } 1484246Sphk} 1494246Sphk 1504246Sphkstruct bits { 1511984Scsgr short b_mask; 1521984Scsgr char b_val; 153} bits[] = { 154 155 { 156 RTF_UP, 'U' 157 }, 158 { 159 RTF_GATEWAY, 'G' 160 }, 161 { 162 RTF_HOST, 'H' 163 }, 164 { 165 RTF_DYNAMIC, 'D' 166 }, 167 { 168 RTF_MODIFIED, 'M' 169 }, 170 { 171 RTF_CLONING, 'C' 172 }, 173 { 174 RTF_XRESOLVE, 'X' 175 }, 176 { 177 RTF_LLINFO, 'L' 178 }, 179 { 180 RTF_REJECT, 'R' 181 }, 182 { 183 0 184 } 185}; 186 187static void 188p_flags(int f, char *format) 189{ 190 if (VarTerm) { 191 char name[33], *flags; 192 register struct bits *p = bits; 193 194 for (flags = name; p->b_mask; p++) 195 if (p->b_mask & f) 196 *flags++ = p->b_val; 197 *flags = '\0'; 198 fprintf(VarTerm, format, name); 199 } 200} 201 202int 203ShowRoute() 204{ 205 struct rt_msghdr *rtm; 206 struct sockaddr *sa; 207 char *sp, *ep, *cp; 208 u_char *wp; 209 int *lp; 210 int needed, nb; 211 u_long mask; 212 int mib[6]; 213 214 if (!VarTerm) 215 return 1; 216 217 mib[0] = CTL_NET; 218 mib[1] = PF_ROUTE; 219 mib[2] = 0; 220 mib[3] = 0; 221 mib[4] = NET_RT_DUMP; 222 mib[5] = 0; 223 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 224 LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 225 return (1); 226 } 227 if (needed < 0) 228 return (1); 229 sp = malloc(needed); 230 if (sp == NULL) 231 return (1); 232 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 233 LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 234 free(sp); 235 return (1); 236 } 237 ep = sp + needed; 238 239 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 240 rtm = (struct rt_msghdr *) cp; 241 sa = (struct sockaddr *) (rtm + 1); 242 mask = 0xffffffff; 243 if (rtm->rtm_addrs == RTA_DST) 244 p_sockaddr(sa, 36); 245 else { 246 wp = (u_char *) cp + rtm->rtm_msglen; 247 p_sockaddr(sa, 16); 248 if (sa->sa_len == 0) 249 sa->sa_len = sizeof(long); 250 sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 251 p_sockaddr(sa, 18); 252 lp = (int *) (sa->sa_len + (char *) sa); 253 if ((char *) lp < (char *) wp && *lp) { 254 LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp); 255 wp = (u_char *) (lp + 1); 256 mask = 0; 257 for (nb = *(char *) lp; nb > 4; nb--) { 258 mask <<= 8; 259 mask |= *wp++; 260 } 261 for (nb = 8 - *(char *) lp; nb > 0; nb--) 262 mask <<= 8; 263 } 264 } 265 fprintf(VarTerm, "%08lx ", mask); 266 p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s "); 267 fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 268 } 269 free(sp); 270 return 0; 271} 272 273/* 274 * Delete routes associated with our interface 275 */ 276void 277DeleteIfRoutes(int all) 278{ 279 struct rt_msghdr *rtm; 280 struct sockaddr *sa; 281 struct in_addr dstnet, gateway, maddr; 282 int needed; 283 char *sp, *cp, *ep; 284 u_long mask; 285 int *lp, nb; 286 u_char *wp; 287 int mib[6]; 288 289 LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 290 291 mib[0] = CTL_NET; 292 mib[1] = PF_ROUTE; 293 mib[2] = 0; 294 mib[3] = 0; 295 mib[4] = NET_RT_DUMP; 296 mib[5] = 0; 297 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 298 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 299 strerror(errno)); 300 return; 301 } 302 if (needed < 0) 303 return; 304 305 sp = malloc(needed); 306 if (sp == NULL) 307 return; 308 309 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 310 LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 311 strerror(errno)); 312 free(sp); 313 return; 314 } 315 ep = sp + needed; 316 317 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 318 rtm = (struct rt_msghdr *) cp; 319 sa = (struct sockaddr *) (rtm + 1); 320 LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 321 " dstnet: %s\n", 322 rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 323 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 324 if (rtm->rtm_addrs != RTA_DST && 325 (rtm->rtm_index == IfIndex) && 326 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 327 LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 328 dstnet = ((struct sockaddr_in *) sa)->sin_addr; 329 wp = (u_char *) cp + rtm->rtm_msglen; 330 if (sa->sa_len == 0) 331 sa->sa_len = sizeof(long); 332 sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 333 gateway = ((struct sockaddr_in *) sa)->sin_addr; 334 lp = (int *) (sa->sa_len + (char *) sa); 335 mask = 0; 336 if ((char *) lp < (char *) wp && *lp) { 337 LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n", 338 rtm->rtm_flags, *lp); 339 wp = (u_char *) (lp + 1); 340 for (nb = *lp; nb > 4; nb--) { 341 mask <<= 8; 342 mask |= *wp++; 343 } 344 for (nb = 8 - *lp; nb > 0; nb--) 345 mask <<= 8; 346 } 347 LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet)); 348 LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 349 LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 350 if (dstnet.s_addr == INADDR_ANY) 351 mask = INADDR_ANY; 352 maddr.s_addr = htonl(mask); 353 OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 354 } 355 } 356 free(sp); 357} 358 359 /* 360 * 960603 - Modified to use dynamic buffer allocator as in ifconfig 361 */ 362 363int 364GetIfIndex(char *name) 365{ 366 char *buffer; 367 struct ifreq *ifrp; 368 int s, len, elen, newIfIndex; 369 struct ifconf ifconfs; 370 371 /* struct ifreq reqbuf[256]; -- obsoleted :) */ 372 int oldbufsize, bufsize = sizeof(struct ifreq); 373 374 s = socket(AF_INET, SOCK_DGRAM, 0); 375 if (s < 0) { 376 LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno)); 377 return (-1); 378 } 379 buffer = malloc(bufsize); /* allocate first buffer */ 380 ifconfs.ifc_len = bufsize; /* Initial setting */ 381 382 /* 383 * Iterate through here until we don't get many more data 384 */ 385 386 do { 387 oldbufsize = ifconfs.ifc_len; 388 bufsize += 1 + sizeof(struct ifreq); 389 buffer = realloc((void *) buffer, bufsize); /* Make it bigger */ 390 LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 391 ifconfs.ifc_len = bufsize; 392 ifconfs.ifc_buf = buffer; 393 if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 394 LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n", 395 strerror(errno)); 396 close(s); 397 free(buffer); 398 return (-1); 399 } 400 } while (ifconfs.ifc_len > oldbufsize); 401 402 ifrp = ifconfs.ifc_req; 403 404 newIfIndex = 1; 405 for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 406 elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 407 if (ifrp->ifr_addr.sa_family == AF_LINK) { 408 LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 409 newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 410 ifrp->ifr_addr.sa_family, elen); 411 if (strcmp(ifrp->ifr_name, name) == 0) { 412 IfIndex = newIfIndex; 413 close(s); 414 free(buffer); 415 return (newIfIndex); 416 } 417 newIfIndex++; 418 } 419 len -= elen; 420 ifrp = (struct ifreq *) ((char *) ifrp + elen); 421 ifrp++; 422 } 423 424 close(s); 425 free(buffer); 426 return (-1); 427} 428