Binary files ax25ipd/ax25ipd and ax25ipddyn/ax25ipd differ diff -ruN ax25ipd/ax25ipd.h ax25ipddyn/ax25ipd.h --- ax25ipd/ax25ipd.h 2009-06-14 01:11:48.000000000 -0700 +++ ax25ipddyn/ax25ipd.h 2009-12-13 13:14:51.403609920 -0800 @@ -118,6 +118,11 @@ #define AXRT_BCAST 1 #define AXRT_DEFAULT 2 +#define AXRT_PERMANENT 4 +#define AXRT_LEARN 8 + + +#define IPSTORAGESIZE 6 /* Bytes needed for call_to_ip */ /* start external prototypes */ /* end external prototypes */ @@ -133,12 +138,16 @@ /* routing.c */ void route_init(void); -void route_add(unsigned char *, unsigned char *, int, unsigned int); +void route_add(char *, unsigned char *, unsigned char *, int, unsigned int); +int route_ipmatch(struct sockaddr_in *, unsigned char *); +unsigned char *retrieveip(unsigned char *, unsigned char *); +void route_process(struct sockaddr_in *, unsigned char *); void bcast_add(unsigned char *); -unsigned char *call_to_ip(unsigned char *); +unsigned char *call_to_ip(unsigned char *, unsigned char *); int is_call_bcast(unsigned char *); void send_broadcast(unsigned char *, int); void dump_routes(void); +void update_dns(unsigned); /* config.c */ void config_init(void); @@ -151,11 +160,13 @@ /* process.c */ void process_init(void); void from_kiss(unsigned char *, int); -void from_ip(unsigned char *, int); +void from_ip(unsigned char *, int, struct sockaddr_in *); /* void do_broadcast(void); where did this go ?? xxx */ void do_beacon(void); int addrmatch(unsigned char *, unsigned char *); +int addrcompare(unsigned char *, unsigned char *); unsigned char *next_addr(unsigned char *); +unsigned char *from_addr(unsigned char *); void add_crc(unsigned char *, int); void dump_ax25frame(char *, unsigned char *, int); Binary files ax25ipd/ax25ipd.o and ax25ipddyn/ax25ipd.o differ Binary files ax25ipd/bpqether.o and ax25ipddyn/bpqether.o differ diff -ruN ax25ipd/config.c ax25ipddyn/config.c --- ax25ipd/config.c 2009-06-14 01:07:11.000000000 -0700 +++ ax25ipddyn/config.c 2009-12-13 13:18:24.875607449 -0800 @@ -292,6 +292,8 @@ return 0; } else if (strcmp(p, "route") == 0) { + char *thost; + uport = 0; flags = 0; @@ -305,15 +307,26 @@ q = strtok(NULL, " \t\n\r"); if (q == NULL) return -1; - he = gethostbyname(q); - if (he != NULL) { - memcpy(tip, he->h_addr_list[0], 4); - } else { /* maybe user specified a numeric addr? */ - j = inet_addr(q); - if (j == -1) - return -5; /* if -1, bad deal! */ + thost = strdup(q); + j = inet_addr(q); + if (j != -1){ /* maybe user specified a numeric addr? */ + flags |= AXRT_PERMANENT; /* Prevent useless dns check on dotted ip */ memcpy(tip, (char *) &j, 4); + if (!j){/* IP of 0.0.0.0. Learn from incoming packets */ + flags |= AXRT_LEARN; + } + } + else { + he = gethostbyname(q); + if (he != NULL) { + memcpy(tip, he->h_addr_list[0], 4); + } else { + j = inet_addr("0.0.0.0");/* try to rescue this idea of checking later.*/ + memcpy(tip, (char *) &j, 4); + fprintf(stderr,"ax25ipd: %s host IP address unknown - will probe it again later\n",thost); + } } + while ((q = strtok(NULL, " \t\n\r")) != NULL) { if (strcmp(q, "udp") == 0) { @@ -334,9 +347,19 @@ if (strchr(q, 'd')) { flags |= AXRT_DEFAULT; } + + /* Test for "permanent" flag */ + if (strchr(q, 'p')) { + flags |= AXRT_PERMANENT; + } + /* Test for "learn" flag */ + if (strchr(q, 'l')) { + flags |= AXRT_LEARN; + } } } - route_add(tip, tcall, uport, flags); + route_add(thost, tip, tcall, uport, flags); + free(thost); return 0; } else if (strcmp(p, "broadcast") == 0) { Binary files ax25ipd/config.o and ax25ipddyn/config.o differ Binary files ax25ipd/crc.o and ax25ipddyn/crc.o differ diff -ruN ax25ipd/.deps/routing.Po ax25ipddyn/.deps/routing.Po --- ax25ipd/.deps/routing.Po 2009-12-07 12:31:40.724371865 -0800 +++ ax25ipddyn/.deps/routing.Po 2009-12-13 13:14:56.129603018 -0800 @@ -52,7 +52,8 @@ /usr/include/termios.h /usr/include/bits/termios.h \ /usr/include/sys/termios.h /usr/include/sys/time.h \ /usr/local/include/netax25/daemon.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h + /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ + /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h /usr/include/stdio.h: @@ -277,3 +278,9 @@ /usr/include/sys/syslog.h: /usr/include/bits/syslog-path.h: + +/usr/include/pthread.h: + +/usr/include/sched.h: + +/usr/include/bits/sched.h: diff -ruN ax25ipd/io.c ax25ipddyn/io.c --- ax25ipd/io.c 2009-06-14 08:42:11.000000000 -0700 +++ ax25ipddyn/io.c 2009-12-08 01:01:00.886377754 -0800 @@ -378,10 +378,11 @@ if (nb == 0) { fflush(stdout); fflush(stderr); + update_dns(60*60); // Once/hour /* just so we go back to the top of the loop! */ continue; } - + update_dns(60*60); // once/hour if (FD_ISSET(ttyfd, &readfds)) { do { n = read(ttyfd, buf, MAX_FRAME); @@ -418,7 +419,7 @@ LOGL4("udpdata from=%s port=%d l=%d\n", (char *) inet_ntoa(from. sin_addr), ntohs(from. sin_port), n); stats.udp_in++; if (n > 0) - from_ip(buf, n); + from_ip(buf, n, &from); } } /* if udp_mode */ @@ -434,7 +435,7 @@ LOGL4("ipdata from=%s l=%d, hl=%d\n", (char *) inet_ntoa(from. sin_addr), n, hdr_len); stats.ip_in++; if (n > hdr_len) - from_ip(buf + hdr_len, n - hdr_len); + from_ip(buf + hdr_len, n - hdr_len, &from); } #ifdef USE_ICMP if (FD_ISSET(icmpsock, &readfds)) { @@ -461,6 +462,9 @@ if (l <= 0) return; + if (* (unsigned *) targetip == 0){ /* If the ip is set to 0 don't send anything. I'm not sure what sending to 0 does, but I don't like the idea. */ + return; + } memcpy((char *) &to.sin_addr, targetip, 4); memcpy((char *) &to.sin_port, Binary files ax25ipd/io.o and ax25ipddyn/io.o differ Binary files ax25ipd/kiss.o and ax25ipddyn/kiss.o differ diff -ruN ax25ipd/Makefile ax25ipddyn/Makefile --- ax25ipd/Makefile 2009-12-13 13:06:10.051599795 -0800 +++ ax25ipddyn/Makefile 2009-12-07 23:55:14.915376717 -0800 @@ -92,7 +92,7 @@ AX25_LIB = -lax25 CC = gcc CCDEPMODE = depmode=gcc3 -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -pthread CPP = gcc -E CPPFLAGS = CYGPATH_W = echo diff -ruN ax25ipd/process.c ax25ipddyn/process.c --- ax25ipd/process.c 2009-06-14 01:07:11.000000000 -0700 +++ ax25ipddyn/process.c 2009-12-08 13:10:43.111379302 -0800 @@ -68,6 +68,7 @@ void from_kiss(unsigned char *buf, int l) { unsigned char *a, *ipaddr; + unsigned char ipstorage[IPSTORAGESIZE];// Provide storage for the IP. To keep all the locking stuff centralized. if (l < 15) { LOGL2("from_kiss: dumped - length wrong!\n"); @@ -105,7 +106,7 @@ } /* end of tnc mode */ /* Lookup the IP address for this route */ - ipaddr = call_to_ip(a); + ipaddr = call_to_ip(a, ipstorage); if (ipaddr == NULL) { if (is_call_bcast(a)) { @@ -146,10 +147,11 @@ * We simply send the packet to the KISS send routine. */ -void from_ip(unsigned char *buf, int l) +void from_ip(unsigned char *buf, int l, struct sockaddr_in *ip_addr) { int port = 0; unsigned char *a; + unsigned char *f; if (!ok_crc(buf, l)) { stats.ip_failed_crc++; @@ -194,6 +196,10 @@ } #endif } /* end of tnc mode */ + + f = from_addr(buf); + route_process(ip_addr, f); + if (!ttyfd_bpq) send_kiss(port, buf, l); else { @@ -277,6 +283,31 @@ } /* + * return 0 if the addresses supplied match + * return a positive or negative value otherwise + */ +int addrcompare(unsigned char *a, unsigned char *b) +{ + signed char diff; + + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "K" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "A" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "9" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "W" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "S" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* "B" */ + if ((diff = (signed char )((*a++ - *b++) & 0xfe))) + return diff; /* ssid */ + return 0; +} + +/* * return pointer to the next station to get this packet */ unsigned char *next_addr(unsigned char *f) @@ -301,6 +332,32 @@ } /* + * return pointer to the last station this packet came from + */ +unsigned char *from_addr(unsigned char *f) +{ + unsigned char *a; + + a = f + 7; +/* If no digis, return the source address */ + if (NO_DIGIS(f)) + return a; + +/* check each digi field. Go to last that has seen it */ + do + a += 7; + while (NOT_LAST(a) && REPEATED(a)); + +/* in DIGI mode: we have set REPEATED already, so the one before is it */ + if (digi || !REPEATED(a)) + a -= 7; + +/* in TNC mode: always the last is it */ + return a; +} + + +/* * tack on the CRC for the frame. Note we assume the buffer is long * enough to have the two bytes tacked on. */ Binary files ax25ipd/process.o and ax25ipddyn/process.o differ diff -ruN ax25ipd/routing.c ax25ipddyn/routing.c --- ax25ipd/routing.c 2009-06-14 01:07:11.000000000 -0700 +++ ax25ipddyn/routing.c 2009-12-13 13:14:25.773601450 -0800 @@ -12,6 +12,8 @@ #include #include #include +#include +#include /* The routing table structure is not visible outside this module. */ @@ -23,6 +25,7 @@ unsigned char pad1; unsigned char pad2; unsigned int flags; /* route flags */ + char *hostnm; /* host name */ struct route_table_entry *next; }; @@ -38,16 +41,31 @@ struct bcast_table_entry *bcast_tbl; +struct callsign_lookup_entry { + unsigned char callsign[7]; + struct route_table_entry *route; + struct callsign_lookup_entry *prev, *next; +}; + +struct callsign_lookup_entry *callsign_lookup; + +time_t last_dns_time; +volatile int threadrunning; +pthread_mutex_t dnsmutex = PTHREAD_MUTEX_INITIALIZER; + /* Initialize the routing module */ void route_init(void) { route_tbl = NULL; default_route = NULL; bcast_tbl = NULL; + callsign_lookup = NULL; + last_dns_time = time(NULL); + threadrunning = 0; } /* Add a new route entry */ -void route_add(unsigned char *ip, unsigned char *call, int udpport, +void route_add(char *host, unsigned char *ip, unsigned char *call, int udpport, unsigned int flags) { struct route_table_entry *rl, *rn; @@ -75,6 +93,7 @@ rn->callsign[i] = call[i] & 0xfe; rn->callsign[6] = (call[6] & 0x1e) | 0x60; rn->padcall = 0; + rn->hostnm = strdup(host); memcpy(rn->ip_addr, ip, 4); rn->udp_port = htons(udpport); rn->pad1 = 0; @@ -100,6 +119,130 @@ return; } +/* For route rn, a different IP is being used. Trigger a DNS check. + * as long as DNS hasn't been checked within 5 minutes (300 seconds) + * */ +void route_updatedyndns(struct sockaddr_in *ip_addr, struct route_table_entry *rn) +{ + if (rn->flags & AXRT_LEARN){ + pthread_mutex_lock(&dnsmutex); + * (unsigned *) rn->ip_addr = (unsigned) ip_addr->sin_addr.s_addr; + pthread_mutex_unlock(&dnsmutex); + } + if (!(rn->flags & AXRT_PERMANENT)){ + LOGL4("received changed ip: %s", call_to_a(rn->callsign)); + update_dns(300); + } +} + +/* Save the calls in a binary tree. This code links new callsigns + * back to an existing route. No new routes are created. */ +void route_updatereturnpath(unsigned char *mycall, struct route_table_entry *rn) +{ + struct callsign_lookup_entry **clookupp = &callsign_lookup; + struct callsign_lookup_entry *clookup = callsign_lookup; + for (;;){ + int chk; + if (!clookup){ + clookup = *clookupp = calloc(sizeof(struct callsign_lookup_entry), 1); + memcpy(clookup->callsign, mycall, 7); + LOGL4("added return route: %s %s %s %d\n", + call_to_a(mycall), + (char *) inet_ntoa(*(struct in_addr *) rn->ip_addr), + rn->udp_port ? "udp" : "ip", ntohs(rn->udp_port)); + + clookup->route = rn; + return; + } + chk = addrcompare(mycall, clookup->callsign); + if (chk > 0){ + clookupp = &clookup->next; + clookup = *clookupp; + } + else if (chk < 0){ + clookupp = &clookup->prev; + clookup = *clookupp; + } + else{ + + if (clookup->route != rn){ + clookup->route = rn; + } + return; + } + } + + +} + + +/* Compare ip_addr to the format used by route_table_entry */ +int route_ipmatch(struct sockaddr_in *ip_addr, unsigned char *routeip) +{ + unsigned char ipstorage[IPSTORAGESIZE]; + return (unsigned) ip_addr->sin_addr.s_addr == * (unsigned *) retrieveip(routeip, ipstorage); +} + + +/* Process calls and ip addresses for routing. The idea behind + * this code that for the routes listed in the ax25ipd.conf file, + * only DNS or the given IP's should be used. But for calls + * that are not referenced in ax25ipd.conf that arrive using + * a known gateway IP, the code links them back to that gateway. + * + * No new routes are created. If a callsign comes in from an + * unknown gateway, it will not create an entry. + * + * if the Callsign for a known route is received, and it does + * not match the current ip for that route, the update_dns code + * is triggered, which should fix the IP based on DNS. + * + * */ +void route_process(struct sockaddr_in *ip_addr, unsigned char *call) +{ + struct route_table_entry *rp; + unsigned char mycall[7]; + int i; + int isroute; + + if (call == NULL) + return; + + for (i = 0; i < 6; i++) + mycall[i] = call[i] & 0xfe; + + mycall[6] = (call[6] & 0x1e) | 0x60; + + rp = route_tbl; + isroute = 0; + while (rp) { + if (addrmatch(mycall, rp->callsign)) { + if (!route_ipmatch(ip_addr, rp->ip_addr)) { + route_updatedyndns(ip_addr, rp); + } + isroute = 1; + } + rp = rp->next; + } + + // Don't use any of the ip lookup code for the routes. + // Also, do not set return paths for broadcast callsigns. + // Not sure if this ever happens. But it's no good if it does. + if (!isroute && !is_call_bcast(call)){ + rp = route_tbl; + while (rp) { + // Only do this once. + if (route_ipmatch(ip_addr, rp->ip_addr)) { + route_updatereturnpath(mycall, rp); + break; + } + rp = rp->next; + } + } + +} + + /* Add a new broadcast address entry */ void bcast_add(unsigned char *call) { @@ -136,17 +279,35 @@ } /* + * It's possible that the thread will update the IP in mid + * memcpy of an ip address, so I changed all the references to + * route_table_entry->ip_addr to use this routine + + * Note that the printfs don't check this + */ + +unsigned char *retrieveip(unsigned char *ip, unsigned char *ipstorage) +{ + if (!ipstorage)return ip; + pthread_mutex_lock(&dnsmutex); + memcpy((void *) ipstorage, (void *) ip, IPSTORAGESIZE); + pthread_mutex_unlock(&dnsmutex); + return ipstorage; +} + +/* * Return an IP address and port number given a callsign. * We return a pointer to the address; the port number can be found * immediately following the IP address. (UGLY coding; to be fixed later!) */ - -unsigned char *call_to_ip(unsigned char *call) + +unsigned char *call_to_ip(unsigned char *call, unsigned char *ipstorage) { struct route_table_entry *rp; unsigned char mycall[7]; int i; - + struct callsign_lookup_entry *clookup; + if (call == NULL) return NULL; @@ -163,11 +324,35 @@ LOGL4("found ip addr %s\n", (char *) inet_ntoa(*(struct in_addr *) rp->ip_addr)); - return rp->ip_addr; + return retrieveip(rp->ip_addr, ipstorage); } rp = rp->next; } + /* Check for callsigns that have been heard on known routes */ + clookup = callsign_lookup; + for (;;){ + int chk; + if (!clookup){ + break; + } + chk = addrcompare(mycall, clookup->callsign); + if (chk > 0){ + clookup = clookup->next; + } + else if (chk < 0){ + clookup = clookup->prev; + } + else{ + LOGL4("found cached ip addr %s\n", + (char *) inet_ntoa(*(struct in_addr *) + clookup->route->ip_addr)); + + return retrieveip(clookup->route->ip_addr, ipstorage); + } + } + + /* * No match found in the routing table, use the default route if * we have one defined. @@ -176,7 +361,7 @@ LOGL4("failed, using default ip addr %s\n", (char *) inet_ntoa(*(struct in_addr *) default_route->ip_addr)); - return default_route->ip_addr; + return retrieveip(default_route->ip_addr, ipstorage); } LOGL4("failed.\n"); @@ -223,7 +408,9 @@ rp = route_tbl; while (rp) { if (rp->flags & AXRT_BCAST) { - send_ip(buf, l, rp->ip_addr); + unsigned char ipstorage[IPSTORAGESIZE]; + + send_ip(buf, l, retrieveip(rp->ip_addr, ipstorage)); } rp = rp->next; } @@ -251,3 +438,60 @@ } fflush(stdout); } + +/* Update the IPs of DNS entries for all routes */ +void *update_dnsthread(void *arg) +{ + struct hostent *he; + struct route_table_entry *rp; + + rp = route_tbl; + while (rp) { + // If IP is 0, DNS lookup failed at startup. + // So check DNS even though it's permanent. + // I think checking the lock on this ip_addr reference + // isn't needed since the main code doesn't change + // ip_addr after startup, and worst case is that it + // does one extra dns check + if ((rp->hostnm[0]) && + (!(rp->flags & AXRT_PERMANENT) || ( * (unsigned *) rp->ip_addr == 0) )){ + LOGL4("Checking DNS for %s\n", rp->hostnm); + he = gethostbyname(rp->hostnm); + if (he != NULL) { + pthread_mutex_lock(&dnsmutex); + * (unsigned *) rp->ip_addr = * (unsigned *) he->h_addr_list[0]; + pthread_mutex_unlock(&dnsmutex); + LOGL4("DNS returned IP=%s\n", (char *) inet_ntoa(*(struct in_addr *) rp->ip_addr)); + } + } + rp = rp->next; + } + threadrunning = 0; + pthread_exit(0); + return 0; +} + +/* check DNS for route IPs. Packets from system whose ip + * has changed trigger a DNS lookup. The + * the timer is needed when both systems are on dynamic + * IPs and they both reset at about the same time. Also + * when the IP changes immediately, but DNS lags. + */ +void update_dns(unsigned wait) +{ + pthread_t dnspthread; + int rc; + + if (threadrunning)return;// Don't start a thread when one is going already. + if (wait && (time(NULL) < last_dns_time + wait))return; + threadrunning = 1; + LOGL4("Starting DNS thread\n"); + last_dns_time = time(NULL); + rc = pthread_create(&dnspthread, NULL, update_dnsthread, (void *) 0); + if (rc){ + LOGL1(" Thread err%d\n", rc); // Should we exit here? + threadrunning = 0; + } + +} + Binary files ax25ipd/routing.o and ax25ipddyn/routing.o differ diff -ruN ax25ipd/run.bat ax25ipddyn/run.bat --- ax25ipd/run.bat 1969-12-31 16:00:00.000000000 -0800 +++ ax25ipddyn/run.bat 2009-12-08 11:35:53.160378651 -0800 @@ -0,0 +1,2 @@ +killall ax25ipd +./ax25ipd -c /etc/ax25/ax25ipd.conf