123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- #include "all.h"
- #include "../ip/ip.h"
- #define DEBUG if(cons.flags&ralloc.flag)print
- enum
- {
- Version= 1,
- /*
- * definitions that are innately tied to BSD
- */
- AF_INET= 2,
- AF_UNSPEC= 0,
- /*
- * 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;
- long 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]))
- goto usage;
- if(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)
- goto usage;
- if(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;
- DEBUG("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;
- DEBUG("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);
- DEBUG("%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)]);
- }
|