#include "all.h" #include "../ip/ip.h" #define dprint(...) if(cons.flags&ralloc.flag)print(__VA_ARGS__) enum{ Version= 1, /* * Packet types. */ Request= 1, Response= 2, Traceon= 3, Traceoff= 4, Infinity= 16, /* infinite hop count */ Maxpacket= 488, /* largest packet body */}; /* * network info */typedef struct Rip Rip;struct Rip{ uchar family[2]; uchar port[2]; uchar addr[Pasize]; uchar pad[8]; uchar metric[4];};typedef struct Ripmsg Ripmsg;struct Ripmsg{ uchar type; uchar vers; uchar pad[2]; Rip rip[1]; /* the rest of the packet consists of routes */}; enum{ Maxroutes= (Maxpacket-4)/sizeof(Ripmsg),}; /* * internal route info */enum{ Nroute = 2*1024, Nhash = 256, /* routing hash buckets */ Nifc = 16,}; typedef struct Route Route;struct Route{ Route *next; uchar dest[Pasize]; uchar mask[Pasize]; uchar gate[Pasize]; int metric; int inuse; Timet time;};struct{ Lock; Route route[Nroute]; Route *hash[Nhash]; int nroute; ulong flag; int dorip;} ralloc; uchar classmask[4][4] ={ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,}; #define CLASS(p) ((*(uchar*)(p))>>6) static void considerroute(Route*);static void deleteroute(Route*);static void printroute(Route*);static void printroutes(void);static void installroute(Route*);static void getmask(uchar*, uchar*);static void maskip(uchar*, uchar*, uchar*);static int equivip(uchar*, uchar*);static void cmd_route(int, char*[]);static ulong rhash(uchar*); voidiprouteinit(void){ cmd_install("route", "subcommand -- ip routes", cmd_route); ralloc.flag = flag_install("route", "-- verbose"); if(!conf.ripoff) ralloc.dorip = 1;} static voidcmd_route(int argc, char *argv[]){ Route r; if(argc < 2) {usage: print("route add dest gate [mask] -- add a route\n"); print("route delete dest -- remote a route\n"); print("route print [dest] -- print routes\n"); print("route ripon -- listen to RIP packets\n"); print("route ripoff -- ignore RIP packets\n"); return; } if(strcmp(argv[1], "ripoff") == 0) ralloc.dorip = 0; else if(strcmp(argv[1], "ripon") == 0) ralloc.dorip = 1; else if(strcmp(argv[1], "add") == 0) { switch(argc){ default: goto usage; case 4: memmove(r.mask, classmask[CLASS(r.dest)], Pasize); break; case 5: if(chartoip(r.mask, argv[4])) goto usage; break; } if(chartoip(r.dest, argv[2]) || chartoip(r.gate, argv[3])) goto usage; r.metric = 0; /* rip can't nuke these */ deleteroute(&r); considerroute(&r); } else if(strcmp(argv[1], "delete") == 0) { if(argc != 3 || chartoip(r.dest, argv[2])) goto usage; deleteroute(&r); } else if(strcmp(argv[1], "print") == 0) { if(argc == 3) { if(chartoip(r.dest, argv[2])) goto usage; printroute(&r); } else printroutes(); }} /* * consider installing a route. Do so only if it is better than what * we have. */static voidconsiderroute(Route *r){ ulong h, i; ulong m, nm; Route *hp, **l; r->next = 0; r->time = time(); r->inuse = 1; lock(&ralloc); h = rhash(r->dest); for(hp = ralloc.hash[h]; hp; hp = hp->next) { if(equivip(hp->dest, r->dest) && equivip(hp->mask, r->mask)) { /* * found a match, replace if better (or much newer) */ if(r->metric < hp->metric || time()-hp->time > 10*60) { memmove(hp->gate, r->gate, Pasize); hp->metric = r->metric; dprint("route: replacement %I & %I -> %I (%d)\n", hp->dest, hp->mask, hp->dest, hp->metric); } if(equivip(r->gate, hp->gate)) hp->time = time(); goto done; } } /* * no match, look for space */ for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++) if(hp->inuse == 0) break; if(hp == &ralloc.route[Nroute]) hp = 0; /* * look for an old entry */ for(i = 0; hp == 0 && i < Nhash; i++) { l = &ralloc.hash[i]; for(hp = *l; hp; hp = *l) { if(time() - hp->time > 10*60 && hp->metric > 0){ *l = hp->next; break; } l = &hp->next; } } if(hp == 0) { print("no more routes"); goto done; } memmove(hp, r, sizeof(Route)); /* * insert largest mask first */ m = nhgetl(hp->mask); for(l = &ralloc.hash[h]; *l; l = &(*l)->next){ nm = nhgetl((*l)->mask); if(nm < m) break; } hp->next = *l; *l = hp; dprint("route: new %I & %I -> %I (%d)\n", hp->dest, hp->mask, hp->dest, hp->metric);done: unlock(&ralloc);} static voiddeleteroute(Route *r){ int h; Route *hp, **l; lock(&ralloc); for(h = 0; h < Nhash; h++) { l = &ralloc.hash[h]; for(hp = *l; hp; hp = *l){ if(equivip(r->dest, hp->dest)) { *l = hp->next; hp->next = 0; hp->inuse = 0; break; } l = &hp->next; } } unlock(&ralloc);} static voidprintroutes(void){ Ifc *i; int h; Route *hp; uchar mask[Pasize]; lock(&ralloc); for(h = 0; h < Nhash; h++) for(hp = ralloc.hash[h]; hp; hp = hp->next) print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate); unlock(&ralloc); print("\nifc's\n"); for(i = enets; i; i = i->next) { hnputl(mask, i->mask); print("addr %I mask %I defgate %I\n", i->ipa, mask, i->netgate); }} static voidprintroute(Route *r){ int h; Route *hp; uchar net[Pasize]; h = rhash(r->dest); for(hp = ralloc.hash[h]; hp; hp = hp->next){ maskip(r->dest, hp->mask, net); if(equivip(hp->dest, net)){ print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate); return; } } print("default * -> %I\n", enets[0].netgate);} voidiproute(uchar *to, uchar *dst, uchar *def){ int h; Route *hp; uchar net[Pasize]; h = rhash(dst); for(hp = ralloc.hash[h]; hp; hp = hp->next) { maskip(dst, hp->mask, net); if(equivip(hp->dest, net)) { def = hp->gate; break; } } memmove(to, def, Pasize);} voidriprecv(Msgbuf *mb, Ifc*){ int n; Rip *r; Ripmsg *m; Udppkt *uh; Route route; if(ralloc.dorip == 0) goto drop; uh = (Udppkt*)mb->data; m = (Ripmsg*)(mb->data + Ensize + Ipsize + Udpsize); if(m->type != Response || m->vers != Version) goto drop; n = nhgets(uh->udplen); n -= Udpsize; n = n/sizeof(Rip); dprint("%d routes from %I\n", n, uh->src); memmove(route.gate, uh->src, Pasize); for(r = m->rip; r < &m->rip[n]; r++){ getmask(route.mask, r->addr); maskip(r->addr, route.mask, route.dest); route.metric = nhgetl(r->metric) + 1; if(route.metric < 1) continue; considerroute(&route); }drop: mbfree(mb);} /* * route's hashed by net, not subnet */static ulongrhash(uchar *d){ ulong h; uchar net[Pasize]; maskip(d, classmask[CLASS(d)], net); h = net[0] + net[1] + net[2]; return h % Nhash;} /* * figure out what mask to use, if we have a direct connected network * with the same class net use its subnet mask. */static voidgetmask(uchar *mask, uchar *dest){ Ifc *i; long ip; ip = nhgetl(dest); for(i = enets; i; i = i->next) if((i->ipaddr & i->cmask) == (ip & i->cmask)) { hnputl(mask, i->mask); return; } memmove(mask, classmask[CLASS(dest)], Pasize);} static voidmaskip(uchar *a, uchar *m, uchar *n){ int i; for(i = 0; i < 4; i++) n[i] = a[i] & m[i];} static intequivip(uchar *a, uchar *b){ int i; for(i = 0; i < 4; i++) if(a[i] != b[i]) return 0; return 1;} longipclassmask(uchar *ip){ return nhgetl(classmask[CLASS(ip)]);}
#include "all.h"
#include "../ip/ip.h"
#define dprint(...) if(cons.flags&ralloc.flag)print(__VA_ARGS__)
enum
{
Version= 1,
/*
* Packet types.
*/
Request= 1,
Response= 2,
Traceon= 3,
Traceoff= 4,
Infinity= 16, /* infinite hop count */
Maxpacket= 488, /* largest packet body */
};
/*
* network info
*/
typedef struct Rip Rip;
struct Rip
{
uchar family[2];
uchar port[2];
uchar addr[Pasize];
uchar pad[8];
uchar metric[4];
};
typedef struct Ripmsg Ripmsg;
struct Ripmsg
{
uchar type;
uchar vers;
uchar pad[2];
Rip rip[1]; /* the rest of the packet consists of routes */
};
enum
{
Maxroutes= (Maxpacket-4)/sizeof(Ripmsg),
};
/*
* internal route info
*/
enum
{
Nroute = 2*1024,
Nhash = 256, /* routing hash buckets */
Nifc = 16,
};
typedef struct Route Route;
struct Route
{
Route *next;
uchar dest[Pasize];
uchar mask[Pasize];
uchar gate[Pasize];
int metric;
int inuse;
Timet time;
};
struct
{
Lock;
Route route[Nroute];
Route *hash[Nhash];
int nroute;
ulong flag;
int dorip;
} ralloc;
uchar classmask[4][4] =
{
0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00,
};
#define CLASS(p) ((*(uchar*)(p))>>6)
static void considerroute(Route*);
static void deleteroute(Route*);
static void printroute(Route*);
static void printroutes(void);
static void installroute(Route*);
static void getmask(uchar*, uchar*);
static void maskip(uchar*, uchar*, uchar*);
static int equivip(uchar*, uchar*);
static void cmd_route(int, char*[]);
static ulong rhash(uchar*);
void
iprouteinit(void)
{
cmd_install("route", "subcommand -- ip routes", cmd_route);
ralloc.flag = flag_install("route", "-- verbose");
if(!conf.ripoff)
ralloc.dorip = 1;
}
static void
cmd_route(int argc, char *argv[])
{
Route r;
if(argc < 2) {
usage:
print("route add dest gate [mask] -- add a route\n");
print("route delete dest -- remote a route\n");
print("route print [dest] -- print routes\n");
print("route ripon -- listen to RIP packets\n");
print("route ripoff -- ignore RIP packets\n");
return;
}
if(strcmp(argv[1], "ripoff") == 0)
ralloc.dorip = 0;
else if(strcmp(argv[1], "ripon") == 0)
ralloc.dorip = 1;
else if(strcmp(argv[1], "add") == 0) {
switch(argc){
default:
goto usage;
case 4:
memmove(r.mask, classmask[CLASS(r.dest)], Pasize);
break;
case 5:
if(chartoip(r.mask, argv[4]))
goto usage;
break;
}
if(chartoip(r.dest, argv[2]) || chartoip(r.gate, argv[3]))
goto usage;
r.metric = 0; /* rip can't nuke these */
deleteroute(&r);
considerroute(&r);
} else if(strcmp(argv[1], "delete") == 0) {
if(argc != 3 || chartoip(r.dest, argv[2]))
goto usage;
deleteroute(&r);
} else if(strcmp(argv[1], "print") == 0) {
if(argc == 3) {
if(chartoip(r.dest, argv[2]))
goto usage;
printroute(&r);
} else
printroutes();
}
}
/*
* consider installing a route. Do so only if it is better than what
* we have.
*/
static void
considerroute(Route *r)
{
ulong h, i;
ulong m, nm;
Route *hp, **l;
r->next = 0;
r->time = time();
r->inuse = 1;
lock(&ralloc);
h = rhash(r->dest);
for(hp = ralloc.hash[h]; hp; hp = hp->next) {
if(equivip(hp->dest, r->dest) && equivip(hp->mask, r->mask)) {
/*
* found a match, replace if better (or much newer)
*/
if(r->metric < hp->metric || time()-hp->time > 10*60) {
memmove(hp->gate, r->gate, Pasize);
hp->metric = r->metric;
dprint("route: replacement %I & %I -> %I (%d)\n",
hp->dest, hp->mask, hp->dest, hp->metric);
}
if(equivip(r->gate, hp->gate))
hp->time = time();
goto done;
}
}
/*
* no match, look for space
*/
for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)
if(hp->inuse == 0)
break;
if(hp == &ralloc.route[Nroute])
hp = 0;
/*
* look for an old entry
*/
for(i = 0; hp == 0 && i < Nhash; i++) {
l = &ralloc.hash[i];
for(hp = *l; hp; hp = *l) {
if(time() - hp->time > 10*60 && hp->metric > 0){
*l = hp->next;
break;
}
l = &hp->next;
}
}
if(hp == 0) {
print("no more routes");
goto done;
}
memmove(hp, r, sizeof(Route));
/*
* insert largest mask first
*/
m = nhgetl(hp->mask);
for(l = &ralloc.hash[h]; *l; l = &(*l)->next){
nm = nhgetl((*l)->mask);
if(nm < m)
break;
}
hp->next = *l;
*l = hp;
dprint("route: new %I & %I -> %I (%d)\n", hp->dest, hp->mask,
hp->dest, hp->metric);
done:
unlock(&ralloc);
}
static void
deleteroute(Route *r)
{
int h;
Route *hp, **l;
lock(&ralloc);
for(h = 0; h < Nhash; h++) {
l = &ralloc.hash[h];
for(hp = *l; hp; hp = *l){
if(equivip(r->dest, hp->dest)) {
*l = hp->next;
hp->next = 0;
hp->inuse = 0;
break;
}
l = &hp->next;
}
}
unlock(&ralloc);
}
static void
printroutes(void)
{
Ifc *i;
int h;
Route *hp;
uchar mask[Pasize];
lock(&ralloc);
for(h = 0; h < Nhash; h++)
for(hp = ralloc.hash[h]; hp; hp = hp->next)
print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate);
unlock(&ralloc);
print("\nifc's\n");
for(i = enets; i; i = i->next) {
hnputl(mask, i->mask);
print("addr %I mask %I defgate %I\n", i->ipa, mask, i->netgate);
}
}
static void
printroute(Route *r)
{
int h;
Route *hp;
uchar net[Pasize];
h = rhash(r->dest);
for(hp = ralloc.hash[h]; hp; hp = hp->next){
maskip(r->dest, hp->mask, net);
if(equivip(hp->dest, net)){
print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate);
return;
}
}
print("default * -> %I\n", enets[0].netgate);
}
void
iproute(uchar *to, uchar *dst, uchar *def)
{
int h;
Route *hp;
uchar net[Pasize];
h = rhash(dst);
for(hp = ralloc.hash[h]; hp; hp = hp->next) {
maskip(dst, hp->mask, net);
if(equivip(hp->dest, net)) {
def = hp->gate;
break;
}
}
memmove(to, def, Pasize);
}
void
riprecv(Msgbuf *mb, Ifc*)
{
int n;
Rip *r;
Ripmsg *m;
Udppkt *uh;
Route route;
if(ralloc.dorip == 0)
goto drop;
uh = (Udppkt*)mb->data;
m = (Ripmsg*)(mb->data + Ensize + Ipsize + Udpsize);
if(m->type != Response || m->vers != Version)
goto drop;
n = nhgets(uh->udplen);
n -= Udpsize;
n = n/sizeof(Rip);
dprint("%d routes from %I\n", n, uh->src);
memmove(route.gate, uh->src, Pasize);
for(r = m->rip; r < &m->rip[n]; r++){
getmask(route.mask, r->addr);
maskip(r->addr, route.mask, route.dest);
route.metric = nhgetl(r->metric) + 1;
if(route.metric < 1)
continue;
considerroute(&route);
}
drop:
mbfree(mb);
}
/*
* route's hashed by net, not subnet
*/
static ulong
rhash(uchar *d)
{
ulong h;
uchar net[Pasize];
maskip(d, classmask[CLASS(d)], net);
h = net[0] + net[1] + net[2];
return h % Nhash;
}
/*
* figure out what mask to use, if we have a direct connected network
* with the same class net use its subnet mask.
*/
static void
getmask(uchar *mask, uchar *dest)
{
Ifc *i;
long ip;
ip = nhgetl(dest);
for(i = enets; i; i = i->next)
if((i->ipaddr & i->cmask) == (ip & i->cmask)) {
hnputl(mask, i->mask);
return;
}
memmove(mask, classmask[CLASS(dest)], Pasize);
}
static void
maskip(uchar *a, uchar *m, uchar *n)
{
int i;
for(i = 0; i < 4; i++)
n[i] = a[i] & m[i];
}
static int
equivip(uchar *a, uchar *b)
{
int i;
for(i = 0; i < 4; i++)
if(a[i] != b[i])
return 0;
return 1;
}
long
ipclassmask(uchar *ip)
{
return nhgetl(classmask[CLASS(ip)]);
}