This is rt_control.c in view mode; [Download] [Up]
/* * $Header: /disk/d/src/devel/gated/dist/src/RCS/rt_control.c,v 2.1 92/02/24 14:12:55 jch Exp $ */ /*%Copyright%*/ /************************************************************************ * * * GateD, Release 2 * * * * Copyright (c) 1990,1991,1992 by Cornell University * * All rights reserved. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY * * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT * * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY * * AND FITNESS FOR A PARTICULAR PURPOSE. * * * * Royalty-free licenses to redistribute GateD Release * * 2 in whole or in part may be obtained by writing to: * * * * GateDaemon Project * * Information Technologies/Network Resources * * 143 Caldwell Hall * * Cornell University * * Ithaca, NY 14853-2602 * * * * GateD is based on Kirton's EGP, UC Berkeley's routing * * daemon (routed), and DCN's HELLO routing Protocol. * * Development of Release 2 has been supported by the * * National Science Foundation. * * * * Please forward bug fixes, enhancements and questions to the * * gated mailing list: gated-people@gated.cornell.edu. * * * * Authors: * * * * Jeffrey C Honig <jch@gated.cornell.edu> * * Scott W Brim <swb@gated.cornell.edu> * * * ************************************************************************* * * * Portions of this software may fall under the following * * copyrights: * * * * Copyright (c) 1988 Regents of the University of California. * * All rights reserved. * * * * Redistribution and use in source and binary forms are * * permitted provided that the above copyright notice and * * this paragraph are duplicated in all such forms and that * * any documentation, advertising materials, and other * * materials related to such distribution and use * * acknowledge that the software was developed by the * * University of California, Berkeley. The name of the * * University may not be used to endorse or promote * * products derived from this software without specific * * prior written permission. THIS SOFTWARE IS PROVIDED * * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * ************************************************************************/ #include "include.h" adv_entry *martian_list = NULL; /* List of Martian nets */ unsigned int adv_n_allocated = 0; /* Number of adv's allocated */ bits gw_bits[] = { {GWF_SOURCE, "Source"}, {GWF_TRUSTED, "Trusted"}, {GWF_ACCEPT, "Accept"}, {GWF_REJECT, "Reject"}, {GWF_QUERY, "Query"}, {0, NULL} }; /* * Allocate an adv_entry. */ adv_entry * #ifdef USE_PROTOTYPES adv_alloc(flag_t flags, proto_t proto) #else /* USE_PROTOTYPES */ adv_alloc(flags, proto) flag_t flags; proto_t proto; #endif /* USE_PROTOTYPES */ { adv_entry *ale; /* Allocate an adv_list entry and put address into it */ ale = (adv_entry *) calloc(1, sizeof(adv_entry)); if (!ale) { trace(TR_ALL, LOG_ERR, "adv_alloc: calloc: %m"); quit(errno); } ale->adv_refcount = 1; ale->adv_flag = flags; ale->adv_proto = proto; trace(TR_PARSE, 0, "adv_alloc: node %X proto %s flags %X refcount %d", ale, trace_bits(rt_proto_bits, ale->adv_proto), ale->adv_flag, ale->adv_refcount); adv_n_allocated++; return (ale); } /* Free an adv_entry list */ void adv_free_list(adv) adv_entry *adv; { static int level = 0; const char *tabs = "\t\t\t\t\t\t"; int allocated = adv_n_allocated; register adv_entry *advn; level++; while (adv) { advn = adv; adv = adv->adv_next; trace(TR_PARSE, 0, "adv_free_list:%.*snode %X proto %s flags %X refcount %d", level, tabs, advn, trace_bits(rt_proto_bits, advn->adv_proto), advn->adv_flag, advn->adv_refcount); if (!--advn->adv_refcount) { switch (advn->adv_flag & ADVF_TYPE) { case ADVF_TANY: case ADVF_TGW: case ADVF_TINTF: case ADVF_TAS: adv_free_list(advn->adv_list); break; case ADVF_TDM: break; default: trace(TR_ALL, LOG_ERR, "adv_free_list: Unknown type %x in adv_entry", advn->adv_flag & ADVF_TYPE); quit(EBADF); } (void) free((caddr_t) advn); adv_n_allocated--; } } if (allocated != adv_n_allocated) { trace(TR_PARSE, 0, "adv_free_list:%.*s%d of %d freed", level, tabs, allocated - adv_n_allocated, allocated); } level--; } /* * Cleanup for a protocol */ void adv_cleanup(n_trusted, n_source, gw_list, accept_list, propagate_list, int_accept, int_propagate) int *n_trusted; int *n_source; gw_entry *gw_list; adv_entry **accept_list; adv_entry **propagate_list; adv_entry ***int_accept; adv_entry ***int_propagate; { gw_entry *gwp; /* Reset gateway list */ if (n_trusted) { *n_trusted = 0; } if (n_source) { *n_source = 0; } GW_LIST(gw_list, gwp) { gwp->gw_flags &= ~(GWF_TRUSTED | GWF_SOURCE); adv_free_list(gwp->gw_accept); gwp->gw_accept = (adv_entry *) 0; adv_free_list(gwp->gw_propagate); gwp->gw_propagate = (adv_entry *) 0; } GW_LISTEND; /* Free accept an propagate lists */ if (accept_list && *accept_list) { adv_free_list(*accept_list); *accept_list = (adv_entry *) 0; } if (propagate_list && *propagate_list) { adv_free_list(*propagate_list); *propagate_list = (adv_entry *) 0; } /* Free the interface accept list */ if (int_accept && *int_accept) { int i = int_index_max; do { adv_free_list((*int_accept)[i]); } while (i--); (void) free((caddr_t) * int_accept); *int_accept = (adv_entry **) 0; } if (int_propagate && *int_propagate) { int i = int_index_max; do { adv_free_list((*int_propagate)[i]); } while (i--); (void) free((caddr_t) * int_propagate); *int_propagate = (adv_entry **) 0; } } /* Look for the specified address in the specified list */ static adv_entry * dmlist_match(list, addr) adv_entry *list; sockaddr_un *addr; { ADV_LIST(list, list) { if (addr->a.sa_family != list->adv_dm.dm_dest.a.sa_family) { continue; } if ((socktype_in(addr)->sin_addr.s_addr & list->adv_dm.dm_mask.in.sin_addr.s_addr) == list->adv_dm.dm_dest.in.sin_addr.s_addr) { break; } } ADV_LISTEND; return (list); } /* * Determine if a route is valid to an interior protocol */ int propagate(rt, proto, proto_list, int_list, gw_list, metric) rt_entry *rt; proto_t proto; adv_entry *proto_list; adv_entry *int_list; adv_entry *gw_list; metric_t *metric; { int i, success, set_met, match = FALSE; adv_entry *adv = NULL; adv_entry *list = NULL; adv_entry *sublist = NULL; adv_entry *lists[3]; /* Build an array of lists to ease processing */ lists[0] = proto_list; lists[1] = int_list; lists[2] = gw_list; if (proto) { /* Default is to propagate this protocol and direct routes */ success = (rt->rt_proto & (RTPROTO_DIRECT | proto)) ? TRUE : FALSE; /* If propagating the same protocol, use incoming metric */ if (rt->rt_proto == proto) { *metric = rt->rt_metric; set_met = FALSE; } else { set_met = TRUE; } } else { /* Default is to propagate only directly attached networks */ success = (rt->rt_proto & RTPROTO_DIRECT) ? TRUE : FALSE; set_met = TRUE; } /* Repeat for each list, gw, int and proto */ i = 2; do { if (lists[i]) { ADV_LIST(lists[i], list) { ADV_LIST(list->adv_list, sublist) { if (rt->rt_proto == sublist->adv_proto) { switch (sublist->adv_flag & ADVF_TYPE) { case ADVF_TANY: match = TRUE; break; case ADVF_TGW: if (rt->rt_sourcegw == sublist->adv_gwp) { match = TRUE; } break; case ADVF_TINTF: if (rt->rt_ifp == sublist->adv_ifp) { match = TRUE; } break; case ADVF_TAS: if (rt->rt_as == sublist->adv_as) { match = TRUE; } break; case ADVF_TDM: /* XXX - should not happen */ break; } if (match) { if (sublist->adv_list) { if (adv = dmlist_match(sublist->adv_list, &rt->rt_dest)) { goto Match; } match = FALSE; } else { success = TRUE; goto Match; } } } } ADV_LISTEND ; } ADV_LISTEND ; success = FALSE; } } while (i--); Match: if (match) { if (adv && (adv->adv_flag & ADVF_NO)) { success = FALSE; } else { success = TRUE; if (set_met) { if (adv && (adv->adv_flag & ADVF_OTMETRIC)) { *metric = adv->adv_metric; } else if (sublist->adv_flag & ADVF_OTMETRIC) { *metric = sublist->adv_metric; } else if (list->adv_flag & ADVF_OTMETRIC) { *metric = list->adv_metric; } } } } return (success); } /* * Determine if a route is valid from an interior protocol. The default * action and preference should be preset into the preference and success * arguments. */ int is_valid_in(dst, proto_list, int_list, gw_list, preference) sockaddr_un *dst; adv_entry *proto_list; adv_entry *int_list; adv_entry *gw_list; pref_t *preference; { int i, success = TRUE; adv_entry *adv = NULL; adv_entry *list = NULL; adv_entry *lists[3]; /* Build an array of lists to ease processing */ lists[0] = proto_list; lists[1] = int_list; lists[2] = gw_list; /* Repeat for each list, gw, int and proto */ i = 2; do { if (lists[i]) { ADV_LIST(lists[i], list) { if (adv = dmlist_match(list->adv_list, dst)) { break; } } ADV_LISTEND; success = FALSE; } } while (i-- && !adv); if (adv) { if (adv->adv_flag & ADVF_NO) { success = FALSE; } else { success = TRUE; if (adv->adv_flag & ADVF_OTPREFERENCE) { *preference = adv->adv_preference; } else if (list->adv_flag & ADVF_OTPREFERENCE) { *preference = list->adv_preference; } } } return (success); } static void martian_init() { const char **ptr; struct sockaddr_in net; adv_entry *adv; static const char *martian_nets[] = { "127.0.0.0", "255.0.0.0", "128.0.0.0", "255.255.0.0", "191.255.0.0", "255.255.255.0", "192.0.0.0", "255.255.255.0", "223.255.255.0", "255.255.255.0", "224.0.0.0", "255.0.0.0", NULL, NULL, }; sockclear_in(&net); for (ptr = martian_nets; *ptr; ptr++) { adv = (adv_entry *) calloc(1, sizeof(*adv)); if (!adv) { trace(TR_ALL, LOG_ERR, "martian_init: calloc %m"); } /* XXX - Should be protocol independent */ sockclear_in(&adv->adv_dm.dm_dest); sockclear_in(&adv->adv_dm.dm_mask); adv->adv_dm.dm_dest.in.sin_addr.s_addr = inet_addr(*ptr); adv->adv_dm.dm_mask.in.sin_addr.s_addr = inet_addr(*(++ptr));; adv->adv_next = martian_list; martian_list = adv; } } /* Return true if said network is a martian */ int is_martian(dst) sockaddr_un *dst; { return (dmlist_match(martian_list, dst) ? 1 : 0); } void control_init() { martian_init(); } /* * Lookup a gateway entry */ gw_entry * gw_lookup(list, proto, addr) gw_entry **list; proto_t proto; sockaddr_un *addr; { gw_entry *gwp; GW_LIST(*list, gwp) { if ((gwp->gw_proto == proto) && equal(&gwp->gw_addr, addr)) { break; } } GW_LISTEND; return (gwp); } /* * Add a gateway entry to end of the list */ gw_entry * gw_add(list, proto, addr) gw_entry **list; proto_t proto; sockaddr_un *addr; { gw_entry *gwp, *gwp_new; gwp_new = (gw_entry *) calloc(1, sizeof(gw_entry)); if (!gwp_new) { trace(TR_ALL, LOG_ERR, "gw_add: calloc: %m"); quit(errno); } if (*list) { GW_LIST(*list, gwp) { if (!gwp->gw_next) { gwp->gw_next = gwp_new; break; } } GW_LISTEND; } else { *list = gwp_new; } gwp_new->gw_addr = *addr; /* struct copy */ gwp_new->gw_proto = proto; return (gwp_new); } /* * Find an existing gw_entry or create a new one */ gw_entry * gw_locate(list, proto, addr) gw_entry **list; proto_t proto; sockaddr_un *addr; { gw_entry *gwp; gwp = gw_lookup(list, proto, addr); if (!gwp) { gwp = gw_add(list, proto, addr); } return (gwp); } /* * Update last heard from timer for a gateway */ gw_entry * gw_timestamp(list, proto, addr) gw_entry **list; proto_t proto; sockaddr_un *addr; { gw_entry *gwp; gwp = gw_locate(list, proto, addr); gwp->gw_time = time_sec; return (gwp); } /* * Dump gateway information */ void gw_dump(fd, name, list) FILE *fd; const char *name; gw_entry *list; { gw_entry *gwp; GW_LIST(list, gwp) { (void) fprintf(fd, "%s %-20A", name, &gwp->gw_addr); if (gwp->gw_time) { (void) fprintf(fd, " last update: %T", gwp->gw_time); } if (gwp->gw_flags) { (void) fprintf(fd, " flags: <%s>", trace_bits(gw_bits, gwp->gw_flags)); } (void) fprintf(fd, "\n"); } GW_LISTEND; } /* * Dump a dest/mask list displaying metric and preference if present */ void control_dmlist_dump(fd, level, name, list) FILE *fd; int level; char *name; adv_entry *list; { adv_entry *adv; const char *tabs = "\t\t\t\t\t\t\t"; ADV_LIST(list, adv) { (void) fprintf(fd, "%.*s%s%.*s%s%-15A mask %-15A", level, tabs, (adv->adv_flag & ADVF_NO) ? "no" : "", name ? strlen(name) : 0, name, name ? "\t" : "", &adv->adv_dm.dm_dest, &adv->adv_dm.dm_mask); switch (adv->adv_flag & ADVF_OTYPE) { case ADVF_OTNONE: (void) fprintf(fd, "\n"); break; case ADVF_OTMETRIC: (void) fprintf(fd, " metric %d\n", adv->adv_metric); break; case ADVF_OTPREFERENCE: (void) fprintf(fd, " preference %d\n", adv->adv_preference); break; } } ADV_LISTEND } /* * Dump the policy database */ void control_dump(fd) FILE *fd; { /* Martian networks */ (void) fprintf(fd, "Martians:\n"); control_dmlist_dump(fd, 2, (char *) 0, martian_list); } void control_accept_dump(fd, level, proto_list, int_list, gw_list) FILE *fd; int level; adv_entry *proto_list; adv_entry **int_list; gw_entry *gw_list; { int interface; int lower; adv_entry *adv; gw_entry *gwp; const char *tabs = "\t\t\t\t\t\t\t"; if (proto_list || int_list || gw_list) { (void) fprintf(fd, "%.*sAccept controls:\n", level++, tabs); } if (proto_list) { ADV_LIST(proto_list, adv) { lower = level; if (adv->adv_flag & ADVF_OTPREFERENCE) { (void) fprintf(fd, "%.*sPreference %d:\n", level, tabs, adv->adv_preference); lower++; } control_dmlist_dump(fd, lower, "listen", adv->adv_list); } ADV_LISTEND } if (int_list) { for (interface = 0; interface <= int_index_max; interface++) { adv = int_list[interface]; if (!adv) { continue; } lower = level + 1; (void) fprintf(fd, "%.*sInterface %s Address %A:\n", level, tabs, adv->adv_ifp->int_name, &adv->adv_ifp->int_addr); if (adv->adv_flag & ADVF_OTPREFERENCE) { (void) fprintf(fd, "%.*sPreference %d:\n", level + 1, tabs, adv->adv_preference); lower++; } control_dmlist_dump(fd, lower, "listen", adv->adv_list); } } if (gw_list) { GW_LIST(gw_list, gwp) { adv = gwp->gw_accept; if (!adv) { continue; } lower = level + 1; (void) fprintf(fd, "%.*sGateway %A:\n", level, tabs, &gwp->gw_addr); if (adv->adv_flag & ADVF_OTPREFERENCE) { (void) fprintf(fd, "%.*sPreference %d:\n", level + 1, tabs, adv->adv_preference); lower++; } control_dmlist_dump(fd, lower, "listen", adv->adv_list); } GW_LISTEND; } } static void control_entry_dump(fd, level, list) FILE *fd; int level; adv_entry *list; { int first = TRUE; const char *tabs = "\t\t\t\t\t\t\t"; adv_entry *adv; if (list) { (void) fprintf(fd, "%.*s", level, tabs); if (list->adv_proto) { (void) fprintf(fd, "Protocol %s ", trace_bits(rt_proto_bits, list->adv_proto)); } adv = list; if (adv) { do { switch (adv->adv_flag & ADVF_TYPE) { case ADVF_TDM: /* XXX - should not happen */ case ADVF_TANY: break; case ADVF_TGW: (void) fprintf(fd, " %s%A", first ? "gateway " : "", &adv->adv_gwp->gw_addr); break; case ADVF_TINTF: (void) fprintf(fd, " %s%A(%s)", first ? "interface " : "", &adv->adv_ifp->int_addr, adv->adv_ifp->int_name); break; case ADVF_TAS: (void) fprintf(fd, " %s%u", first ? "as " : "", adv->adv_as); break; } first = FALSE; } while ((adv = adv->adv_next) && !(adv->adv_flag & ADVF_FIRST)); } switch (list->adv_flag & ADVF_OTYPE) { case ADVF_OTNONE: break; case ADVF_OTMETRIC: (void) fprintf(fd, " metric %d", list->adv_metric); break; case ADVF_OTPREFERENCE: (void) fprintf(fd, " preference %d", list->adv_preference); break; } } (void) fprintf(fd, "\n"); } void control_propagate_list_dump(fd, level, list) FILE *fd; int level; adv_entry *list; { int lower; adv_entry *adv; const char *tabs = "\t\t\t\t\t\t\t"; if (list) { ADV_LIST(list, list) { lower = level; if (list->adv_flag & ADVF_OTMETRIC) { (void) fprintf(fd, "%.*sMetric %d:\n", level, tabs, list->adv_metric); lower++; } adv = list->adv_list; if (adv) { do { control_entry_dump(fd, lower, adv); if (adv->adv_list) { control_dmlist_dump(fd, lower + 1, "announce", adv->adv_list); } do { adv = adv->adv_next; } while (adv && !(adv->adv_flag & ADVF_FIRST)); } while (adv); } } ADV_LISTEND } } void control_propagate_dump(fd, level, proto_list, int_list, gw_list) FILE *fd; int level; adv_entry *proto_list; adv_entry **int_list; gw_entry *gw_list; { int interface; adv_entry *adv; gw_entry *gwp; const char *tabs = "\t\t\t\t\t\t\t"; if (proto_list || int_list || gw_list) { (void) fprintf(fd, "%.*sPropagate controls:\n", level++, tabs); } control_propagate_list_dump(fd, level, proto_list); if (int_list) { for (interface = 0; interface <= int_index_max; interface++) { adv = int_list[interface]; if (adv) { (void) fprintf(fd, "%.*sInterface %s Address %A:\n", level, tabs, adv->adv_ifp->int_name, &adv->adv_ifp->int_addr); control_propagate_list_dump(fd, level + 1, adv); } } } if (gw_list) { GW_LIST(gw_list, gwp) { adv = gwp->gw_propagate; if (adv) { (void) fprintf(fd, "%.*sGateway %A:\n", level, tabs, &gwp->gw_addr); control_propagate_list_dump(fd, level + 1, adv); } } GW_LISTEND; } } void control_exterior_dump(fd, level, func, list) FILE *fd; int level; void (*func) (); adv_entry *list; { adv_entry *adv; const char *tabs = "\t\t\t\t\t\t\t"; ADV_LIST(list, adv) { (void) fprintf(fd, "%.*sAS %u:\n", level, tabs, adv->adv_as); func(fd, level + 1, adv->adv_list, (adv_entry **) 0, (gw_entry *) 0); (void) fprintf(fd, "\n"); } ADV_LISTEND; } adv_entry * #ifdef USE_PROTOTYPES control_exterior_locate(adv_entry * list, as_t as) #else /* USE_PROTOTYPES */ control_exterior_locate(list, as) adv_entry *list; as_t as; #endif /* USE_PROTOTYPES */ { if (list) { ADV_LIST(list, list) { if (list->adv_as == as) { break; } } ADV_LISTEND; } return ((list && list->adv_list) ? list->adv_list : list); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.