|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 18465 (0x4821) Types: TextFile Names: »gw2.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z« └─⟦b503a39fe⟧ └─⟦this⟧ »kip/gw2.c«
/* * AppleTalk / Ethernet Gateway; part 2. * * (c) 1986, Stanford Univ. CSLI. * May be used but not sold without permission. * * $Header: gw2.c,v 4.1 88/11/01 19:49:25 sw0l Locked $ */ #include "gw.h" #include "gwctl.h" #include "fp/pbuf.h" #include "ab.h" #include "inet.h" #include "fp/cmdmacro.h" #ifdef SNMP #include "snmp.h" #include "mib.h" #include "snmp_vars.h" #endif #include "glob.h" /* * NBP packet input from appletalk (abreceive). */ nbpinput(p) struct pbuf *p; { register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize); register op = (n->control & nbpControlMask); Entity ent; register iaddr; /* * if bridge request, put on backround queue * to nbpback, who will send all the LkUp's. */ if (op == nbpBrRq) { K_PENQNP(&nbpq, p); return; } /* else packet is a LkUp or LkUpReply, check for local names */ nbpgetent(n->tuple.name, &ent); /* break up tuple name entity */ /* * if lookup reply for us, complete any pending requests. */ if (op == nbpLkUpReply) { if (ddp.dstNode != ifab.if_dnode || strcmp(ent.type, "IPADDRESS") != 0 || (iaddr = atoip(ent.obj, 99)) == 0 ) goto drop; /* pass the address reply to ARP and ipdad modules */ arpgotreply(&ifab, iaddr, &n->tuple.addr); ipdadreply(&ifab, iaddr, &n->tuple.addr); goto drop; } /* * else lookup; handle requests for our IP related services. */ if (strcmp(ent.type, "IPGATEWAY") == 0) { iaddr = conf.ipaddr; goto replyus; } if (strcmp(ent.type, "IPADDRESS") == 0) { if ((iaddr = atoip(ent.obj, 99)) == 0 || ipbroadcast(iaddr)) goto drop; /* dont reply to bad addresses */ if (abmatch(iaddr)) goto replyus; } if (strcmp(ent.type, "=") == 0 && strcmp(ent.obj, "=") == 0) { iaddr = conf.ipaddr; strcpy(ent.type, "IPGATEWAY"); goto reply; } goto drop; replyus: if (getaroute(n->tuple.addr.net) == 0) goto drop; /* not our responsibility */ reply: iptoa(iaddr, ent.obj); /* Should always return with "my zone" */ ddp.length = nbpsetent(n->tuple.name, ent.obj, ent.type, "*") + ddpSize + nbpMinSize; ddp.checksum = 0; ddp.srcNet = source_if->if_dnet; ddp.srcNode = source_if->if_dnode; ddp.dstNet = n->tuple.addr.net; ddp.dstNode = n->tuple.addr.node; ddp.dstSkt = n->tuple.addr.skt; n->tuple.addr.net = ddp.srcNet; n->tuple.addr.node = ddp.srcNode; n->tuple.addr.skt = ddpIPSkt; ddp.srcSkt = nbpNIS; n->control = nbpLkUpReply + 1; p->p_len = ddp.length + lapSize; bcopy((caddr_t)&ddp, p->p_off+lapSize, ddpSize); routeddp(p, 0, 0); return; drop: K_PFREE(p); } /* * Queue an NBP lookup request. If net/node is non-zero, * does an 'nbpconfirm' operation. */ nbplookup(ent, net, node) Entity *ent; { register struct NBP *n; register struct pbuf *p; struct DDP d; K_PGET(PT_DATA, p); if (p == 0) return; n = (struct NBP *)(p->p_off + lapSize + ddpSize); n->control = nbpLkUp + 1; n->id = 0; n->tuple.enume = 0; n->tuple.addr.net = d.srcNet = ifab.if_dnet; n->tuple.addr.node = d.srcNode = ifab.if_dnode; n->tuple.addr.skt = d.srcSkt = d.dstSkt = nbpNIS; d.checksum = 0; d.type = ddpNBP; d.length = nbpsetent(n->tuple.name, ent->obj, ent->type, ent->zone) + ddpSize + nbpMinSize; p->p_off[2] = lapDDP; p->p_len = d.length + lapSize; if (net) { /* wants an nbpconfirm */ d.dstNet = net; d.dstNode = node; } bcopy((caddr_t)&d, p->p_off + lapSize, ddpSize); if (net) { bcopy((caddr_t)&d, (caddr_t)&ddp, ddpSize); routeddp(p, 0, 0); } else { K_PENQNP(&nbpq, p); } } /* 'static' */ struct aroute *nback_arfrom; struct aroute *nback_arnext; short nback_zoneindex; /* * NBP 'backround'. Check nbpq for BrRq's to be sent out as LkUp's. * Sends to one net per call/loop. */ nbpback() { register struct aroute *ar, *arx; register struct pbuf *pq, *p; struct NBP *n; register int zi; u_char i; u_char *zone; if ((pq = nbpq.pq_head) == 0) return; /* if nothing to do */ if (sendq->pq_head) return; /* delay if ether sendq exists */ if ((ar = nback_arnext) == 0) { /* first time for this packet */ ar = nback_arnext = &aroute[0]; bcopy(pq->p_off + lapSize, (caddr_t)&ddp, ddpSize); ddp.checksum = 0; ddp.dstNode = 0xFF; /* dstNet set below */ n = (struct NBP *)(pq->p_off + lapSize + ddpSize); n->control = nbpLkUp + 1; zi = n->tuple.name[0] + 1; /* skip name */ /* should check to see if we are off end of pkt */ if (zi > 33) goto drop; if (n->tuple.name[zi] > 32) goto drop; zi += n->tuple.name[zi] + 1; /* skip type */ zone = &n->tuple.name[zi]; /* zone length + zone */ if (zone[0] > 32) goto drop; /* find route */ for (arx = &aroute[0]; arx < &aroute[NAROUTE]; ++arx) if (arx->net == ddp.srcNet) break; /* forget it if we can't figure out where it came from */ if (arx >= &aroute[NAROUTE]) goto drop; /* Translate '*' to my zone */ if (zone[0] == 1 && zone[1] == '*') { /* Choose the zone for the interface message came from */ if (arx->zone == 0) goto drop; i = azone[arx->zone][0]+1; bcopy(azone[arx->zone], zone, i); i -= 2; /* -2 for '\01*' */ pq->p_len += i; ddp.length += i; } nback_arfrom = arx; /* copy deferred from above so we can reset ddp length */ bcopy((caddr_t)&ddp, pq->p_off + lapSize, ddpSize); if ((nback_zoneindex = zipfind(zone, 1)) == -1) goto drop; } n = (struct NBP *)(pq->p_off + lapSize + ddpSize); /* * for each net, route a packet there */ for ( ; ar < &aroute[NAROUTE] ; ++ar) { if (ar->net == 0) continue; /* continue if wrong zone and the zone is not all zones */ /* make sure allzones is set before using */ if (ar->zone != nback_zoneindex && !(allzones && ar->zone == allzones)) continue; K_PGET(PT_DATA, p); if (p == 0) return; /* try later */ /* copy efficiently in 4 byte (long) chunks */ bcopy(pq->p_off, p->p_off, ((pq->p_len + 3) & 0xFFFC)); p->p_len = pq->p_len; /* * Set the net number directly into the ddp header, * without copying. Setup a few ddp.xxx globals for * the convenience of 'routeddp'. */ p->p_off[7] = (ar->net >> 8); p->p_off[8] = ar->net; ddp.srcNet = nback_arfrom->net; ddp.dstNet = ar->net; ddp.dstNode = 0xFF; ddp.dstSkt = ddp.srcSkt = nbpNIS; routeddp(p, porttoif[nback_arfrom->port], 0); nback_arnext = ar + 1; return; } drop: /* done with this BrRq, dequeue it */ K_PDEQNP(&nbpq, pq); K_PFREE(pq); nback_arnext = 0; } /* * Ask "who has" IP address addr, using NBP on my locally * connected segments. */ nbpwhohasip(addr) iaddr_t addr; { Entity ent; iptoa(addr, ent.obj); strcpy(ent.zone, "*"); strcpy(ent.type, "IPADDRESS"); nbplookup(&ent, 0, 0); } /* * Unpack an nbp entity starting at cp. * Returns total size of entity (for skipping to next tuple). */ nbpgetent(cp, ent) register char *cp; register Entity *ent; { char *oldcp; register i; oldcp = cp; i = (*cp & 0x1F); bcopy(cp+1, ent->obj, i); ent->obj[i] = 0; cp += i+1; i = (*cp & 0x1F); bcopy(cp+1, ent->type, i); ent->type[i] = 0; cp += i+1; i = (*cp & 0x1F); bcopy(cp+1, ent->zone, i); ent->zone[i] = 0; cp += i+1; return (cp - oldcp); } /* * Setup an nbp entity field with object, type, and zone strings. * Returns length of this tuple. */ nbpsetent(cp, obj, type, zone) register char *cp; char *obj, *type, *zone; { register char *oldcp = cp; register i; *cp = i = strlen(obj); bcopy(obj, cp+1, i); cp += i+1; *cp = i = strlen(type); bcopy(type, cp+1, i); cp += i+1; *cp = i = strlen(zone); bcopy(zone, cp+1, i); cp += i+1; return (cp - oldcp); } /* * Filter out certain NBP lookup replies to provide (some) * security for LaserWriter and other servers outside the local zone. */ nbpfilter(p) struct pbuf *p; { register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize); register u_char *cp; register i,j; register struct aroute *ar; char filter = 0; if ((n->control & nbpControlMask) != nbpLkUpReply) return (0); cp = n->tuple.name; if (conf.flags & conf_tildefilter) { i = *cp; if (cp[i] == '~') filter++; } if(conf.flags & conf_laserfilter) { cp += *cp + 1; if (*cp == 11 && strncmpci(cp+1, "LaserWriter", 11) == 0) filter++; } if (filter == 0) return (0); /* * if srcNet is in my zone but dstNet is not, * drop it. */ i = j = 0; for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) { if (ar->net == ddp.srcNet) i = ar->zone; if (ar->net == ddp.dstNet) j = ar->zone; if (i && j) break; } if (i != aroute[0].zone) return (0); if (j == i) return (0); return (1); /* drop it */ } /* * Process an IP packet directed to the gateway's own IP address. * These are usually control packets such as admin configure/ * net table, debug packets, ICMP packets. */ ip4me(p) struct pbuf *p; { register struct ip *ip = (struct ip *)p->p_off; int hlen = ip->ip_hl << 2; struct udp *u; register struct gwdb *g; register struct aaconf *m; struct icmp *ic; if (ip->ip_p == IPPROTO_ICMP) goto icmp; if (ip->ip_p == IPPROTO_UDP) goto udp; #ifdef SNMP mib_ip.ipInUnknownProtos++; #endif drop: K_PFREE(p); return; udp: #ifdef SNMP mib_ip.ipInDelivers++; #endif u = (struct udp *)(p->p_off + hlen); switch (u->dst) { case aaPort: #ifdef SNMP mib_udp.udpInDatagrams++; #endif m = (struct aaconf *)(u+1); /* this may be too inflexible, but so be it */ if (m->magic != aaMagic || ipRus(ip->ip_src) == 0) goto drop; /* not from our friends */ switch (m->type) { case aaCONF: confready(m); break; case aaROUTEI: azoneinit = 0; /* need to fetch zone info */ case aaROUTE: case aaROUTEQ: artinput(m, ip->ip_src); break; case aaRESTART: K_EXECUTE(); break; #ifdef notdef case aaZONE: zipinit(m); break; #endif case aaZONEQ: zipinput(m->stuff,(int)m->count, ip->ip_src); break; } goto drop; case gwdbPort: #ifdef SNMP mib_udp.udpInDatagrams++; #endif goto gwdb; case rebPort: #ifdef SNMP mib_udp.udpInDatagrams++; #endif if (ip->ip_dst != conf.ipaddr) goto drop; bcopy((caddr_t)(u+1) + lapSize, &ddp, ddpSize); p->p_off += hlen + sizeof *u; p->p_len -= hlen + sizeof *u; routeddp(p, 0, 0); return; #ifdef SNMP case SNMP_PORT: mib_udp.udpInDatagrams++; snmp_input(p); goto drop; default: mib_udp.udpNoPorts++; #endif SNMP } goto drop; gwdb: g = (struct gwdb *)(u+1); if (ip->ip_src != conf.ipdebug || g->magic != gwdbMagic) goto drop; switch (g->op) { case gwdbRead: bcopy(g->address, g->data, g->count); break; case gwdbWrite: bcopy(g->data, g->address, g->count); break; default: g->op = 0; /* error reply code */ } /* * Assume the packet length does not change. */ u->checksum = 0; #ifdef SNMP mib_udp.udpOutDatagrams++; #endif flip: ip->ip_dst = ip->ip_src; ip->ip_src = conf.ipaddr; ip->ip_sum = 0; ip->ip_sum = in_cksum((caddr_t)ip, hlen); routeip(p, 0, 0); return; icmp: #ifdef SNMP mib_ip.ipInDelivers++; mib_icmpInMsgs++; #endif ic = (struct icmp *)(p->p_off + hlen); #ifdef SNMP mib_icmpInCount[ic->icmp_type]++; #endif if (ic->icmp_type == ICMP_ECHO) { ic->icmp_type = ICMP_ECHOREPLY; ic->icmp_cksum = 0; ic->icmp_cksum = in_cksum((caddr_t)ic, ip->ip_len - hlen); #ifdef SNMP mib_icmpOutCount[ic->icmp_type]++; mib_icmpOutMsgs++; #endif goto flip; } goto drop; } /* * IP are us. Returns true if this IP address is 'one of us': * the administrator or one of the configured gateways. */ ipRus(ia) iaddr_t ia; { register struct aroute *ar; register f; f = (arouteKbox|arouteAA); if (ia == conf.ipadmin || ia == conf.ipdebug) return (1); for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) { if (ar->net == 0) continue; if ((ar->flags & f) != f) continue; if (ar->node == ia) return (1); } return (0); } /* * Process a DDP packet directed to the gateway's own address. * Called from routeddp with the ddp header already unpacked * in global struct 'ddp'. */ ddp4me(p) register struct pbuf *p; { register struct ATP *a; register struct IPGP *ig; switch (ddp.type) { case ddpNBP: if (ddp.dstSkt != nbpNIS) goto drop; nbpinput(p); return; case ddpRTMP: case ddpRTMPR: if (ddp.dstSkt != rtmpSkt) goto drop; rtmpinput(p); return; case ddpECHO: if (ddp.dstSkt != echoSkt) goto drop; if (p->p_off[lapSize+ddpSize] != echoRequest) goto drop; p->p_off[lapSize+ddpSize] = echoReply; ddpreply(p, echoSkt); return; case ddpZIP: if (ddp.dstSkt == zipSkt) zipinput(p->p_off+lapSize+ddpSize, p->p_len-lapSize-ddpSize,0L); goto drop; case ddpATP: if (ddp.dstSkt == zipSkt) { zipatp(p); return; } if (ddp.dstSkt != ddpIPSkt) goto drop; break; default: goto drop; } a = (struct ATP *)(p->p_off + lapSize + ddpSize); if ((ddp.length & ddpLengthMask) < (ddpSize + sizeof *a + 4)) goto drop; if ((a->control & (~atpFlagMask)) != atpReqCode) goto drop; ig = (struct IPGP *)(a + 1); switch (ig->op) { case ipgpAssign: case ipgpServer: ipgassign(ig, ig->op); break; /* case ipgpName: ipgname(ig); goto drop;*/ default: strcpy(ig->string, "bad op"); ig->op = -1; break; } a->control = atpRspCode + atpEOM; a->bitmap = 0; /* +1 is to account for null */ p->p_len=lapSize+ddpSize+sizeof(*a)+ipgpMinSize+strlen(ig->string)+1; ddpreply(p, ddpIPSkt); return; drop: K_PFREE(p); } /* * IPGATEWAY request to assign address. */ ipgassign(ig, op) register struct IPGP *ig; { register struct ipdad *d; struct ipdad *od; int dmax, otimer; register i; if (op == ipgpServer) goto server; /* skip most of this */ dmax = conf.ipdynamic; otimer = 0; for (d = &ipdad[0], i = 0 ; i < dmax ; d++,i++ ) { if (d->timer == 0) { otimer = ipdadTimerMax; od = d; } else if (d->timer > otimer) { otimer = d->timer; od = d; } if (d->net == ddp.srcNet && d->node == ddp.srcNode) goto assign; } if (otimer <= ipdadTimerMin) { ig->op = -1; strcpy(ig->string, "no free address"); return; } d = od; assign: d->net = ddp.srcNet; d->node = ddp.srcNode; d->timer = 1; ig->ipaddress = (d - &ipdad[0]) + conf.ipaddr + conf.ipstatic + 1; if (i == dmax) /* if this address may have been reassigned */ arpdelete(ig->ipaddress); server: ig->string[0] = 0; ig->ipname = conf.ipname; ig->ipbroad = conf.ipbroad; ig->ipfile = conf.ipfile; bcopy((caddr_t)conf.ipother, (caddr_t)ig->ipother, sizeof ig->ipother); } short ipd_index, ipd_timer, ipd_first; /* 'static' */ /* * Timeout unused ipdad table entries. Called once per second, sends * one 'tickle' per minute to each 'active' IP address client. * Sends at most one NBP per second. */ ipdadtimer() { Entity ent; register struct ipdad *d; if (conf.ipdynamic == 0) return; /* * This one-time code runs between seconds 25 to 30 after the * gateway is booted. It does an nbplookup request for * all IPADDRESSes so we can initially fill in our table. */ if (ipd_first < 30) { ipd_first++; if (ipd_first < 25) /* wait for RTMPs to establish */ return; strcpy(ent.obj, "="); strcpy(ent.type, "IPADDRESS"); strcpy(ent.zone, "*"); nbplookup(&ent, 0, 0); return; } /* * This code runs every second after startup. Step thru * the table pinging active entries. */ ipd_timer++; d = &ipdad[ipd_index]; for ( ; ; d++, ipd_index++) { if (ipd_index >= conf.ipdynamic) { if (ipd_timer < 60) return; ipd_timer = ipd_index = 0; d = &ipdad[0]; } /* dont ping empty or really old entries */ if (d->timer == 0 || d->timer == ipdadTimerMax) continue; if (++d->timer > ipdadTimerMin) continue; iptoa(conf.ipaddr + conf.ipstatic + 1 + ipd_index, ent.obj); strcpy(ent.type, "IPADDRESS"); strcpy(ent.zone, "*"); nbplookup(&ent, d->net, d->node); ipd_index++; return; } } /* * Reply to ipdadtimer NBP 'tickle' received; reset timer. */ ipdadreply(ifp, iaddr, daddr) struct ifnet *ifp; iaddr_t iaddr; register AddrBlock *daddr; { register struct ipdad *d; register i; i = iaddr - (conf.ipaddr + conf.ipstatic + 1); if (i < 0 || i >= conf.ipdynamic) return; d = &ipdad[i]; d->timer = 1; d->net = daddr->net; d->node = daddr->node; } /* * Convert ASCII dot notation string 's' to long ip address. * 'n' is optional byte count. * Returns address, or 0 if error. */ atoip(s, n) register char *s; { register addr, dots, num; dots = addr = num = 0; for ( ; ; s++, n--) { if (n == 0 || *s == '.' || *s == 0) { dots++; if (num > 255) return (0); addr = (addr << 8) + num; num = 0; if (n && *s == '.') continue; if (dots != 4) return (0); else return (addr); } if (*s >= '0' && *s <= '9') num = (num*10) + (*s - '0'); else return (0); } } /* * Convert IP address to ASCII. Converts 'n' to string at 's'. * Returns number of bytes in s (minus null). */ iptoa(n, s) register n; register char *s; { char buf[20]; register char *cp; int i; register b; cp = buf; for (i = 0 ; i < 4 ; i++) { b = (n & 0xFF); n >>= 8; if (b) { while (b) { *cp++ = (b % 10) + '0'; b /= 10; } } else { *cp++ = '0'; } *cp++ = '.'; } cp -= 2; /* skip last dot */ i = 0; while (cp >= buf) { *s++ = *cp--; i++; } *s = 0; return (i); } /* * Setup the standard IP header fields for a destination */ setiphdr(p, dst) struct pbuf *p; iaddr_t dst; { register struct ip *ip = (struct ip *)p->p_off; ip->ip_v = IPVERSION; ip->ip_hl = sizeof(*ip) >> 2; ip->ip_tos = 0; ip->ip_len = p->p_len; ip->ip_id = ipid++; ip->ip_off = 0; ip->ip_ttl = IPFRAGTTL; ip->ip_p = IPPROTO_UDP; ip->ip_src = conf.ipaddr; ip->ip_dst = dst; ip->ip_sum = 0; ip->ip_sum = in_cksum((caddr_t)ip, sizeof(*ip)); } /* * assumes ddp.type already set and that the reply goes to the node specified * by: (ddp.srcNet, ddp.srcNode, ddp.srcSkt) * * p should be aligned so offset points to start of lap data with room * for lap + long ddp. p->p_len should record the correct length * * skt is outgoing socket * */ ddpreply(p, skt) register struct pbuf *p; int skt; { u_char dst; register struct DDP *dp = &ddp; dp->length = p->p_len - lapSize; dp->checksum = 0; dp->dstNet = dp->srcNet; dp->dstNode = dp->srcNode; dp->dstSkt = dp->srcSkt; dp->srcNet = source_if->if_dnet; dp->srcNode = source_if->if_dnode; dp->srcSkt = skt; bcopy((caddr_t)dp, p->p_off+lapSize, ddpSize); routeddp(p, 0, 0); }