|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983, 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)tables.c 5.17 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Routing Table Management Daemon ! 26: */ ! 27: #include "defs.h" ! 28: #include <sys/ioctl.h> ! 29: #include <errno.h> ! 30: #include <sys/syslog.h> ! 31: ! 32: #ifndef DEBUG ! 33: #define DEBUG 0 ! 34: #endif ! 35: ! 36: #ifdef RTM_ADD ! 37: #define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);} ! 38: #else ! 39: #define FIXLEN(s) { } ! 40: #endif ! 41: ! 42: int install = !DEBUG; /* if 1 call kernel */ ! 43: ! 44: /* ! 45: * Lookup dst in the tables for an exact match. ! 46: */ ! 47: struct rt_entry * ! 48: rtlookup(dst) ! 49: struct sockaddr *dst; ! 50: { ! 51: register struct rt_entry *rt; ! 52: register struct rthash *rh; ! 53: register u_int hash; ! 54: struct afhash h; ! 55: int doinghost = 1; ! 56: ! 57: if (dst->sa_family >= af_max) ! 58: return (0); ! 59: (*afswitch[dst->sa_family].af_hash)(dst, &h); ! 60: hash = h.afh_hosthash; ! 61: rh = &hosthash[hash & ROUTEHASHMASK]; ! 62: again: ! 63: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 64: if (rt->rt_hash != hash) ! 65: continue; ! 66: if (equal(&rt->rt_dst, dst)) ! 67: return (rt); ! 68: } ! 69: if (doinghost) { ! 70: doinghost = 0; ! 71: hash = h.afh_nethash; ! 72: rh = &nethash[hash & ROUTEHASHMASK]; ! 73: goto again; ! 74: } ! 75: return (0); ! 76: } ! 77: ! 78: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ ! 79: ! 80: /* ! 81: * Find a route to dst as the kernel would. ! 82: */ ! 83: struct rt_entry * ! 84: rtfind(dst) ! 85: struct sockaddr *dst; ! 86: { ! 87: register struct rt_entry *rt; ! 88: register struct rthash *rh; ! 89: register u_int hash; ! 90: struct afhash h; ! 91: int af = dst->sa_family; ! 92: int doinghost = 1, (*match)(); ! 93: ! 94: if (af >= af_max) ! 95: return (0); ! 96: (*afswitch[af].af_hash)(dst, &h); ! 97: hash = h.afh_hosthash; ! 98: rh = &hosthash[hash & ROUTEHASHMASK]; ! 99: ! 100: again: ! 101: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 102: if (rt->rt_hash != hash) ! 103: continue; ! 104: if (doinghost) { ! 105: if (equal(&rt->rt_dst, dst)) ! 106: return (rt); ! 107: } else { ! 108: if (rt->rt_dst.sa_family == af && ! 109: (*match)(&rt->rt_dst, dst)) ! 110: return (rt); ! 111: } ! 112: } ! 113: if (doinghost) { ! 114: doinghost = 0; ! 115: hash = h.afh_nethash; ! 116: rh = &nethash[hash & ROUTEHASHMASK]; ! 117: match = afswitch[af].af_netmatch; ! 118: goto again; ! 119: } ! 120: #ifdef notyet ! 121: /* ! 122: * Check for wildcard gateway, by convention network 0. ! 123: */ ! 124: if (dst != &wildcard) { ! 125: dst = &wildcard, hash = 0; ! 126: goto again; ! 127: } ! 128: #endif ! 129: return (0); ! 130: } ! 131: ! 132: rtadd(dst, gate, metric, state) ! 133: struct sockaddr *dst, *gate; ! 134: int metric, state; ! 135: { ! 136: struct afhash h; ! 137: register struct rt_entry *rt; ! 138: struct rthash *rh; ! 139: int af = dst->sa_family, flags; ! 140: u_int hash; ! 141: ! 142: if (af >= af_max) ! 143: return; ! 144: (*afswitch[af].af_hash)(dst, &h); ! 145: flags = (*afswitch[af].af_rtflags)(dst); ! 146: /* ! 147: * Subnet flag isn't visible to kernel, move to state. XXX ! 148: */ ! 149: FIXLEN(dst); ! 150: FIXLEN(gate); ! 151: if (flags & RTF_SUBNET) { ! 152: state |= RTS_SUBNET; ! 153: flags &= ~RTF_SUBNET; ! 154: } ! 155: if (flags & RTF_HOST) { ! 156: hash = h.afh_hosthash; ! 157: rh = &hosthash[hash & ROUTEHASHMASK]; ! 158: } else { ! 159: hash = h.afh_nethash; ! 160: rh = &nethash[hash & ROUTEHASHMASK]; ! 161: } ! 162: rt = (struct rt_entry *)malloc(sizeof (*rt)); ! 163: if (rt == 0) ! 164: return; ! 165: rt->rt_hash = hash; ! 166: rt->rt_dst = *dst; ! 167: rt->rt_router = *gate; ! 168: rt->rt_timer = 0; ! 169: rt->rt_flags = RTF_UP | flags; ! 170: rt->rt_state = state | RTS_CHANGED; ! 171: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst); ! 172: if (rt->rt_ifp == 0) ! 173: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 174: if ((state & RTS_INTERFACE) == 0) ! 175: rt->rt_flags |= RTF_GATEWAY; ! 176: rt->rt_metric = metric; ! 177: insque(rt, rh); ! 178: TRACE_ACTION("ADD", rt); ! 179: /* ! 180: * If the ioctl fails because the gateway is unreachable ! 181: * from this host, discard the entry. This should only ! 182: * occur because of an incorrect entry in /etc/gateways. ! 183: */ ! 184: if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 185: ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { ! 186: if (errno != EEXIST && gate->sa_family < af_max) ! 187: syslog(LOG_ERR, ! 188: "adding route to net/host %s through gateway %s: %m\n", ! 189: (*afswitch[dst->sa_family].af_format)(dst), ! 190: (*afswitch[gate->sa_family].af_format)(gate)); ! 191: perror("SIOCADDRT"); ! 192: if (errno == ENETUNREACH) { ! 193: TRACE_ACTION("DELETE", rt); ! 194: remque(rt); ! 195: free((char *)rt); ! 196: } ! 197: } ! 198: } ! 199: ! 200: rtchange(rt, gate, metric) ! 201: struct rt_entry *rt; ! 202: struct sockaddr *gate; ! 203: short metric; ! 204: { ! 205: int add = 0, delete = 0, newgateway = 0; ! 206: struct rtentry oldroute; ! 207: ! 208: FIXLEN(gate); ! 209: FIXLEN(&(rt->rt_router)); ! 210: FIXLEN(&(rt->rt_dst)); ! 211: if (!equal(&rt->rt_router, gate)) { ! 212: newgateway++; ! 213: TRACE_ACTION("CHANGE FROM ", rt); ! 214: } else if (metric != rt->rt_metric) ! 215: TRACE_NEWMETRIC(rt, metric); ! 216: if ((rt->rt_state & RTS_INTERNAL) == 0) { ! 217: /* ! 218: * If changing to different router, we need to add ! 219: * new route and delete old one if in the kernel. ! 220: * If the router is the same, we need to delete ! 221: * the route if has become unreachable, or re-add ! 222: * it if it had been unreachable. ! 223: */ ! 224: if (newgateway) { ! 225: add++; ! 226: if (rt->rt_metric != HOPCNT_INFINITY) ! 227: delete++; ! 228: } else if (metric == HOPCNT_INFINITY) ! 229: delete++; ! 230: else if (rt->rt_metric == HOPCNT_INFINITY) ! 231: add++; ! 232: } ! 233: if (delete) ! 234: oldroute = rt->rt_rt; ! 235: if ((rt->rt_state & RTS_INTERFACE) && delete) { ! 236: rt->rt_state &= ~RTS_INTERFACE; ! 237: rt->rt_flags |= RTF_GATEWAY; ! 238: if (metric > rt->rt_metric && delete) ! 239: syslog(LOG_ERR, "%s route to interface %s (timed out)", ! 240: add? "changing" : "deleting", ! 241: rt->rt_ifp->int_name); ! 242: } ! 243: if (add) { ! 244: rt->rt_router = *gate; ! 245: rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router); ! 246: if (rt->rt_ifp == 0) ! 247: rt->rt_ifp = if_ifwithnet(&rt->rt_router); ! 248: } ! 249: rt->rt_metric = metric; ! 250: rt->rt_state |= RTS_CHANGED; ! 251: if (newgateway) ! 252: TRACE_ACTION("CHANGE TO ", rt); ! 253: #ifndef RTM_ADD ! 254: if (add && install) ! 255: if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) ! 256: perror("SIOCADDRT"); ! 257: if (delete && install) ! 258: if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) ! 259: perror("SIOCDELRT"); ! 260: #else ! 261: if (delete && install) ! 262: if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) ! 263: perror("SIOCDELRT"); ! 264: if (add && install) { ! 265: if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) ! 266: perror("SIOCADDRT"); ! 267: } ! 268: #endif ! 269: } ! 270: ! 271: rtdelete(rt) ! 272: struct rt_entry *rt; ! 273: { ! 274: ! 275: TRACE_ACTION("DELETE", rt); ! 276: FIXLEN(&(rt->rt_router)); ! 277: FIXLEN(&(rt->rt_dst)); ! 278: if (rt->rt_metric < HOPCNT_INFINITY) { ! 279: if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE) ! 280: syslog(LOG_ERR, ! 281: "deleting route to interface %s? (timed out?)", ! 282: rt->rt_ifp->int_name); ! 283: if (install && ! 284: (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 && ! 285: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) ! 286: perror("SIOCDELRT"); ! 287: } ! 288: remque(rt); ! 289: free((char *)rt); ! 290: } ! 291: ! 292: rtdeleteall(sig) ! 293: int sig; ! 294: { ! 295: register struct rthash *rh; ! 296: register struct rt_entry *rt; ! 297: struct rthash *base = hosthash; ! 298: int doinghost = 1; ! 299: ! 300: again: ! 301: for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { ! 302: rt = rh->rt_forw; ! 303: for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { ! 304: if (rt->rt_state & RTS_INTERFACE || ! 305: rt->rt_metric >= HOPCNT_INFINITY) ! 306: continue; ! 307: TRACE_ACTION("DELETE", rt); ! 308: if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 && ! 309: ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) ! 310: perror("SIOCDELRT"); ! 311: } ! 312: } ! 313: if (doinghost) { ! 314: doinghost = 0; ! 315: base = nethash; ! 316: goto again; ! 317: } ! 318: exit(sig); ! 319: } ! 320: ! 321: /* ! 322: * If we have an interface to the wide, wide world, ! 323: * add an entry for an Internet default route (wildcard) to the internal ! 324: * tables and advertise it. This route is not added to the kernel routes, ! 325: * but this entry prevents us from listening to other people's defaults ! 326: * and installing them in the kernel here. ! 327: */ ! 328: rtdefault() ! 329: { ! 330: extern struct sockaddr inet_default; ! 331: ! 332: rtadd(&inet_default, &inet_default, 1, ! 333: RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL); ! 334: } ! 335: ! 336: rtinit() ! 337: { ! 338: register struct rthash *rh; ! 339: ! 340: for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) ! 341: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 342: for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) ! 343: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; ! 344: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.