|
|
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);
}