diff options
author | Bjørn Mork <bjorn@mork.no> | 2015-05-15 10:25:21 +0200 |
---|---|---|
committer | Bjørn Mork <bjorn@mork.no> | 2015-05-15 10:25:21 +0200 |
commit | b8c5c3b44362778c099531f7a905c56a0423bcef (patch) | |
tree | e9ccaff5d19f39e7bc58734e1b5babf4025a3a9c /networking | |
parent | b1b227fa5e00d08af047ab9a012211b66c6b0f13 (diff) |
ripe-atlas-fw: imported version 46504650
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Diffstat (limited to 'networking')
-rw-r--r-- | networking/Config.in | 6 | ||||
-rw-r--r-- | networking/Kbuild | 2 | ||||
-rw-r--r-- | networking/atlasinit.c | 740 | ||||
-rw-r--r-- | networking/rptaddrs.c | 775 | ||||
-rw-r--r-- | networking/rptra6.c | 2 |
5 files changed, 1520 insertions, 5 deletions
diff --git a/networking/Config.in b/networking/Config.in index cdf067a..84c89ad 100644 --- a/networking/Config.in +++ b/networking/Config.in @@ -705,11 +705,11 @@ config RPTRA6 help Report received IPv6 router advertisements -config RPTADDR6 - bool "rptaddr6" +config RPTADDRS + bool "rptaddrs" default n help - Report IPv6 addresses and routes + Report addresses, routes, dns both static and dynamic config RXTXRPT bool "rxtxrpt" diff --git a/networking/Kbuild b/networking/Kbuild index ddb143a..d550ed4 100644 --- a/networking/Kbuild +++ b/networking/Kbuild @@ -32,7 +32,7 @@ lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o lib-$(CONFIG_RPTRA6) += rptra6.o -lib-$(CONFIG_RPTADDR6) += rptaddr6.o +lib-$(CONFIG_RPTADDRS) += rptaddrs.o lib-$(CONFIG_RXTXRPT) += rxtxrpt.o lib-$(CONFIG_SLATTACH) += slattach.o lib-$(CONFIG_SSLGETCERT) += sslgetcert.o diff --git a/networking/atlasinit.c b/networking/atlasinit.c new file mode 100644 index 0000000..121b508 --- /dev/null +++ b/networking/atlasinit.c @@ -0,0 +1,740 @@ +/* RIPEAtlas + * All the configurable variables - and some non configurables too + * Usage1: ./init_resp_parse < init_messagefile + * Usage2: ./init_resp_parse init_messagefile + * $Id: $ + */ + + +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <stdarg.h> +#include "atlasinit.h" + +//#ifndef NOTBUSYBOX +/* compiled to busybox. tested on 1.13 */ +#include "libbb.h" +//#endif + +#define ERROR 1 +#define INFO 2 +#define ATLAS_DEFAULT_WAIT 100 +#define OPT_STRING "rcdsi:I:" +#define ATLAS_WAIT 0 + +enum +{ + OPT_REG_INIT = (1 << 0), /* r */ + OPT_CNT_INIT = (1 << 1), /* c */ + OPT_CNT_HELLO = (1 << 2), /* d */ + OPT_SINCELAST = (1 << 3), /* s */ + OPT_P_TO_R_INIT = (1 << 4), /* i */ +}; + +#define DBQ(str) "\"" #str "\"" + +/********************************************************************* + * Set these constants to your liking + */ +static int read_wait (FILE *read_from, const char *type, int waittime); +static int reg_init_main( int argc, char *argv[] ); +static int con_hello_main( int argc, char *argv[] ); +static int con_init_main( int argc, char *argv[] ); +static void since_last_main (int argc, char *argv[]); +static void print_token_ver (FILE * write_to, int flag_rereg); + +const char atlas_log_file[]="./probe.log"; +const int atlas_log_level=INFO; + +const char atlas_contr_known_hosts[]="./known_hosts_controllers"; +const char atlas_rereg_timestamp[]="./rereg_time.sh"; +const char atlas_con_hello[]="./con_hello.txt"; +const char atlas_con_session_id[]="./con_session_id.txt"; +const char atlas_force_reg[] = "./force_reg.sh"; +const char atlas_netconfig_v4[] = "./netconfig_v4.vol"; +const char atlas_netconfig_v6[] = "./netconfig_v6.vol"; +const char atlas_resolv_conf[] = "./resolv.conf.vol"; +const char atlas_network_v4_info[] = "/home/atlas/status/network_v4_info.txt"; +const char atlas_network_v4_static_info[] = "/home/atlas/status/network_v4_static_info.txt"; +const char atlas_network_v4_static_info_json[] = "/home/atlas/status/network_v4_static_info.json"; +const char atlas_network_v6_static_info[] = "/home/atlas/status/network_v6_static_info.txt"; +const char atlas_network_v6_static_info_json[] = "/home/atlas/status/network_v6_static_info.json"; +const char atlas_network_dns_static_info[] = "/home/atlas/status/network_dns_static_info.txt"; +const char atlas_network_dns_static_info_json[] = "/home/atlas/status/network_dns_static_info.json"; + +const int max_lines = 16; /* maximum lines we'll process */ +const int min_rereg_time = 100; +const int max_rereg_time = 28*24*3600; /* 28d */ +const int default_rereg_time = 7*24*3600; /* 7d */ +char *str_reason; +const char *str_device; + +/**********************************************************************/ + +static char line[ATLAS_BUF_SIZE]; + +#ifdef NOTBUSYBOX +int main( int argc, char *argv[] ) +#else +int atlasinit_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int atlasinit_main( int argc, char *argv[] ) +#endif +{ + int opt = 0; + + if(argc > 1) + { + str_device= NULL; + opt = getopt32(argv, OPT_STRING, &str_reason, &str_device); + argv += optind; + argc -= optind; + argc++; // AA Hack + } + else + { // AA improve + // we are called without an option decide which is default + reg_init_main( argc, argv); + } + + if(opt & OPT_REG_INIT) + { + reg_init_main( argc, argv); + } + else if(opt & OPT_CNT_HELLO) + { + con_hello_main(argc, argv); + } + else if ( opt & OPT_CNT_INIT) + { + con_init_main(argc, argv); + + } + else if (opt & OPT_SINCELAST) + { + since_last_main(argc, argv); + } + else if(opt & OPT_P_TO_R_INIT) + { + print_token_ver(stdout, 1); + } + + return 0; +} + +static void print_token_ver (FILE * write_to, int flag_rereg) +{ +float root_fs_ver = 0; +FILE *fp = xfopen_for_read("/proc/version"); +FILE *fpv = fopen("/home/atlas/state/FIRMWARE_APPS_VERSION", "r"); + char *my_mac ; + +bzero( line, ATLAS_BUF_SIZE ); +fscanf (fp, "%s", line); +fscanf (fp, "%s", line); +fscanf (fp, "%s", line); +if(fpv) + fscanf (fpv, "%f", &root_fs_ver); + else + root_fs_ver=3100; + if(flag_rereg > 0) + fprintf(write_to, "P_TO_R_INIT\n"); + my_mac = getenv("ETHER_SCANNED"); + fprintf(write_to, "TOKEN_SPECS probev1 %s", line); + if (my_mac != NULL) + fprintf(write_to, "-%s ", my_mac ); + fprintf(write_to, " %d\n", (int)root_fs_ver); + if(flag_rereg > 0) + fprintf(write_to, "REASON_FOR_REGISTRATION %s\n", str_reason); + fclose(fp); +} + +static void since_last_main (int argc, char *argv[]) +{ + FILE *thenfile; + int then; + time_t mytime; + + mytime = time(0); + + if ( argc == 1) { + printf("%d\n", (int)mytime); + } + else { + if ((thenfile = fopen(argv[0], "r")) == NULL) { + printf("%d\n", (int)mytime); + } + else { + fscanf(thenfile, "%d", &then); + printf("%d\n", (int)(mytime - then)); + } + } +} + +static int con_hello_main( int argc, char *argv[] ) +{ + /* read response from P_TO_C_HELLO */ + FILE *read_from = stdin; + int ret = 0; + long tmp_long; + + time_t mytime = time(0); + time_t con_time; + if( argc > 1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"CONTROLLER_TIMESTAMP ", 21)==0 ) { + int timediff2 ; + + sscanf( line+21, "%ld", &tmp_long); + con_time= tmp_long; + timediff2 = ( mytime - con_time ) * ( mytime - con_time ); + printf ("Mytime %d controller time %d\n",(int)mytime , (int)con_time); + if( timediff2 > 4 ) { + struct timeval tval; + + atlas_log( INFO, "Time difference is %d seconds, set time ?\n", timediff2); + printf ("Set mytime \n"); + tval.tv_sec = con_time; + tval.tv_usec = 0; + settimeofday( &tval, NULL); + } + + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + } + else { + fprintf (stderr, "P_TO_C_HELLO response is unexptedte %s\n", line); + } + + if (argc > 1 ) + fclose (read_from); + return ret; +} +static int con_init_main( int argc, char *argv[] ) +{ + FILE *read_from = stdin; + int ret = 0; + + int remote_port; + if( argc > 1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"REMOTE_PORT", 11)==0 ) { + sscanf( line+11, "%d", &remote_port); + printf ("REMOTE_PORT=%d\n", remote_port); + } + else if ( strncmp(line,"SESSION_ID", 10)==0 ) + { + FILE *f = fopen( atlas_con_hello, "wt" ); + FILE *f1 = fopen( atlas_con_session_id, "wt" ); + + fprintf (f, "P_TO_C_HELLO\nSESSION_ID %s", line+11); + fprintf (f1, "\nSESSION_ID %s\n", line+11); + print_token_ver (f, 0 ); + fclose (f); + fclose (f1); + + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + } + else if (strncmp(line,"WAIT\n",5) == 0 ) + { + read_wait(read_from, "CON_WAIT_TIMER", ATLAS_WAIT); + } + else if (strncmp(line,"REFUSED\n",8) == 0 ) + { + FILE *f = fopen( atlas_force_reg, "wt" ); + + unlink(atlas_con_hello); + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + fprintf (f,"REASON=%s\n", line+8); + fclose(f); + + } + else { + char *p = strchr(line,'\n'); + if( p!=NULL ) *p = '\0'; + atlas_log( ERROR, "OK expected, got \"%s\" instead\n", line ); + read_wait(read_from, "CON_WAIT_TIMER", ATLAS_DEFAULT_WAIT); /* we got error the only action from probe is wait. so force it*/ + ret = 1; + } + + if (argc > 1 ) + fclose (read_from); + return ret; + +} +static int read_wait (FILE *read_from, const char *type, int waittime) +{ + unsigned delay; + time_t mytime = time(0); + if(waittime < 1) + { + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + if( strncmp(line,"TIMEOUT", 7)==0 ) { + sscanf( line+7, "%d", &delay); + } + else + { + delay = ATLAS_DEFAULT_WAIT; + } + } + else + { + delay = waittime; + } + mytime = time(0); + if(delay > max_rereg_time ) { + atlas_log( ERROR, "Reregister time %d is too high\n", delay ); + delay = max_rereg_time; + } + if(delay < min_rereg_time ) { + atlas_log( ERROR, "Reregister time %d is too high\n", delay ); + delay = min_rereg_time; + } + printf ("%s=%u\n", type, (uint)(mytime + delay)); + return (delay); +} + +static int reg_init_main( int argc, char *argv[] ) +{ + + time_t mytime; + FILE *read_from = stdin; + + char *token; + const char *search = " "; + const char *search_nl = " \n"; + int ret = 0; + int first; + + int reregister_time = default_rereg_time; + mytime = time(NULL); + + if (!str_device) + str_device= "eth0"; + + if( argc >1 ) { + read_from = fopen( argv[0], "rt" ); + if( read_from==NULL ) { + atlas_log( ERROR, "Cannot read from file %s\n", argv[1] ); + return 1; + } + } + + /* read OK */ + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + if( strncmp(line,"OK\n",3) == 0 ) { + int l=1; + int n_controller = 0; + char *host_name; + char *type; + char *key; + int do_rm_v4_static_info; + int do_rm_v6_static_info; + int do_rm_dns_static_info; + + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + + do_rm_v4_static_info= 1; + do_rm_v6_static_info= 1; + do_rm_dns_static_info= 1; + while( !feof(read_from) && l<=max_lines ) { + if( strncmp(line,"CONTROLLER ", 11)==0 ) { + FILE *f; + char *ptr; + + n_controller++; + /* TODO: one can check whether it's about the right length and syntax */ + + ptr = strchr( line+11, ' ' ); + if( ptr==NULL ) { + atlas_log( ERROR, "CONTROLLER line is suspicious (line %d)\n", l ); + return 1; + } + f = fopen( atlas_contr_known_hosts, "wt" ); + if( f==NULL ) { + atlas_log( ERROR, "Unable to append to file %s\n", atlas_contr_known_hosts ); + return 1; + } + //fprintf( f, "%s\n", line+11 ); + token = strtok(line+11, search); + /* host name */ + printf ("CONTROLLER_%d_HOST=%s\n", n_controller, token); + fprintf( f, "%s ", token); + host_name = token; + + token = strtok(NULL, search); + printf ("CONTROLLER_%d_PORT=%s\n", n_controller, token); + token = strtok(NULL, search); + fprintf( f, "%s ", token); + type = token; + token = strtok(NULL, search); + fprintf( f, "%s\n", token); + key = token; + fprintf (f, "ipv4.%s %s %s\n", host_name, type, key); + fprintf (f, "ipv6.%s %s %s\n", host_name, type, key); + fclose(f); + + } + else if( strncmp(line,"REREGISTER ", 11)==0 ) + { + sscanf( line+11, "%d", &reregister_time ); + read_wait(read_from, "REREG_TIMER", reregister_time); + + } + else if( strncmp(line,"REGSERVER_TIMESTAMP ", 20)==0 ) { + int regserver_time; + int timediff2 ; + + sscanf( line+20, "%d", ®server_time ); + timediff2 = ( mytime - regserver_time ) * ( mytime - regserver_time ); + if( timediff2 > 4 ) { + struct timeval tval; + + atlas_log( INFO, "Time difference is %d seconds, what to do now?\n", (int)(mytime-regserver_time) ); + + tval.tv_sec = regserver_time; + tval.tv_usec = 0; + settimeofday( &tval, NULL); + } + } + else if( strncmp(line,"FIRMWARE_KERNEL ", 16)==0 ) + { + unsigned root_fs_ver = 0; + token = strtok (line+16, search); // version + sscanf (token, "%u", &root_fs_ver); + printf("FIRMWARE_KERNEL_VERSION=%u\n", + root_fs_ver); + token = strtok(NULL, search); // alg + printf("FIRMWARE_KERNEL_CS_ALG=%s\n", token); + + token = strtok(NULL, search); // comp hash + printf("FIRMWARE_KERNEL_CS_COMP=%s\n", token); + + token = strtok(NULL, search); // uncomp hash + + printf("FIRMWARE_KERNEL_CS_UNCOMP=%s\n", token); + token = strtok(NULL, search); // url hash + printf( "FIRMWARE_KERNEL=%s\n", token) ; + + } + else if( strncmp(line,"FIRMWARE_APPS ", 14)==0 ) + { + unsigned root_fs_ver = 0; + token = strtok (line+14, search); // version + sscanf (token, "%u", &root_fs_ver); + printf("FIRMWARE_APPS_VERSION=%u\n", + root_fs_ver); + token = strtok(NULL, search); // alg + printf("FIRMWARE_APPS_CS_ALG=%s\n", token); + + token = strtok(NULL, search); // comp hash + printf("FIRMWARE_APPS_CS_COMP=%s\n", token); + + token = strtok(NULL, search); // uncomp hash + + printf("FIRMWARE_APPS_CS_UNCOMP=%s\n", token); + token = strtok(NULL, search); // url hash + printf( "FIRMWARE_APPS=%s\n", token) ; + + } + + else if( strncmp(line,"DHCPV4 False ", 13)==0 ) + { + FILE *f = fopen(atlas_netconfig_v4, "wt"); + char *ipv4_address; + char *netmask; + char *broadcast; + char *ipv4_gw; + + if( f==NULL ) { + atlas_log( ERROR, "Unable to create %s\n", atlas_netconfig_v4 ); + return 1; + } + + // Statically configured probe. +//DHCPV4 False IPV4ADDRESS 10.0.0.151 IPV4NETMASK 255.255.255.0 IPV4NETWORK 10.0.0.0 IPV4BROADCAST 10.0.0.255 IPV4GATEWAY 10.0.0.137 + // fprintf (f, "%s\n", line); + token = strtok(line+13, search); //IPV4ADDRESS + token = strtok(NULL, search); // <address> + fprintf (f, "/sbin/ifconfig %s 0.0.0.0\n", + str_device); + fprintf (f, "/sbin/ifconfig %s:1 %s ", + str_device, token); + ipv4_address = token; + token = strtok(NULL, search); // IPV4NETMASK + token = strtok(NULL, search); // + fprintf (f, "netmask %s ", token); + netmask = token; + token = strtok(NULL, search); // IPV4NETWORK + token = strtok(NULL, search); // + token = strtok(NULL, search); // IPV4BROADCAST + token = strtok(NULL, search); // + fprintf (f, "broadcast %s \n", token); + broadcast = token; + token = strtok(NULL, search); // IPV4GATEWAY + token = strtok(NULL, search); // + fprintf (f, "/sbin/route add default gw %s\n", token); + ipv4_gw = token; + ipv4_gw[(strlen(ipv4_gw) - 1)] = '\0'; + + // put parts in the shell script to make network info file + + fprintf (f, "echo \"P_TO_C_NETWORK_UPDATE\" > %s \n", atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_LOCAL_ADDR %s\" >> %s \n", ipv4_address, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_NETMASK %s\" >> %s \n", netmask, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_BROADCAST %s\" >> %s \n", broadcast, atlas_network_v4_info ); + fprintf (f, "echo \"IPV4_GW %s\" >> %s \n",ipv4_gw , atlas_network_v4_info ); + fprintf (f, "echo \"DHCP False \" >> %s \n", atlas_network_v4_info ); + + + // second file for static + fprintf (f, "echo \"STATIC_IPV4_LOCAL_ADDR %s\" > %s \n", ipv4_address, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_NETMASK %s\" >> %s \n", netmask, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_BROADCAST %s\" >> %s \n", broadcast, atlas_network_v4_static_info ); + fprintf (f, "echo \"STATIC_IPV4_GW %s\" >> %s \n",ipv4_gw , atlas_network_v4_static_info ); + fprintf(f, "echo '" + DBQ(static-inet-addresses) " : [ { " + DBQ(inet-addr) ": " DBQ(%s) ", " + DBQ(netmask) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) + " } ], " + DBQ(static-inet-routes) " : [ { " + DBQ(destination) ": " DBQ(0.0.0.0) ", " + DBQ(netmask) ": " DBQ(0.0.0.0) ", " + DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) + " } ]' > %s\n", + ipv4_address, + netmask, + str_device, + ipv4_gw, + str_device, + atlas_network_v4_static_info_json); + // ping the gateway + fprintf (f, "ping -c 2 -q %s \n", ipv4_gw); + fprintf (f, "IPV4_GW=%s; export IPV4_GW\n", ipv4_gw); + + fclose(f); + + do_rm_v4_static_info= 0; + } + //DHCPV6 False IPV6ADDRESS <address> IPV6PREFIXLEN <prefix> IPV6GATEWAY <gateway>]| [DHCPV6 True ] + else if( strncmp(line,"DHCPV6 False ", 13)==0 ) + { + FILE *f = fopen(atlas_netconfig_v6, "wt"); + char *ipv6_address; + char *prefixlen; + char *ipv6_gw; + + if( f==NULL ) { + atlas_log( ERROR, "Unable to create %s\n", atlas_netconfig_v6 ); + return 1; + } + + // Statically configured probe. + + //fprintf (f, "%s\n", line); + token = strtok(line+13, search); //IPV6ADDRESS + token = strtok(NULL, search); // <address> + ipv6_address = token; + token = strtok(NULL, search); // IPV6PREFIXLEN + token = strtok(NULL, search); // + prefixlen = token; + fprintf (f, "/sbin/ifconfig %s 0.0.0.0\n", + str_device); + fprintf (f, "/sbin/ifconfig %s %s/%s\n", + str_device, ipv6_address, prefixlen); + + token = strtok(NULL, search); // IPV6GATEWAY + token = strtok(NULL, search); // + ipv6_gw = token; + ipv6_gw[(strlen(ipv6_gw) - 1)] = '\0'; + ///sbin/route -A inet6 add default gw fe80::13:0:0:1 dev eth0 + fprintf (f, + "/sbin/route -A inet6 add default gw %s dev %s\n", + ipv6_gw, str_device); + // second file for static network info + fprintf (f, "echo \"STATIC_IPV6_LOCAL_ADDR %s/%s\" > %s \n", ipv6_address, prefixlen, atlas_network_v6_static_info ); + fprintf (f, "echo \"STATIC_IPV6_GW %s\" >> %s \n",ipv6_gw , atlas_network_v6_static_info ); + + fprintf(f, "echo '" + DBQ(static-inet6-addresses) ": [ { " + DBQ(inet6-addr) ": " DBQ(%s) ", " + DBQ(prefix-length) ": %s, " + DBQ(interface) ": " DBQ(%s) " } ], " + DBQ(static-inet6-routes) ": [ { " + DBQ(destination) ": " DBQ(::) ", " + DBQ(prefix-length) " : 0, " + DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " } ]" + "' > %s\n", + ipv6_address, prefixlen, str_device, + ipv6_gw, str_device, + atlas_network_v6_static_info_json); + + + fclose(f); + do_rm_v6_static_info= 0; + } + else if( strncmp(line,"DNS_SERVERS ", 11)==0 ) + { + FILE *f, *f1, *f2; + + f = fopen(atlas_resolv_conf, "wt"); + if( f==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_resolv_conf ); + return 1; + } + + f1 = fopen(atlas_network_dns_static_info, "wt"); + if( f1==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_network_dns_static_info); + fclose(f); + return 1; + } + f2 = fopen(atlas_network_dns_static_info_json, + "wt"); + if( f2==NULL ) { + atlas_log(ERROR, + "Unable to create %s\n", + atlas_network_dns_static_info_json); + fclose(f); + fclose(f1); + return 1; + } + + + // Statically configured probe. + //DNS_SERVERS 8.8.8.8 194.109.6.66 + // fprintf (f, "%s\n", line); + token = strtok(line+11, search_nl); // + fprintf (f1, "STATIC_DNS"); + fprintf(f2, DBQ(static-dns) ": [ "); + + first= 1; + while (token != NULL) + { + fprintf (f, "nameserver %s\n", token); + fprintf (f1, " %s", token); + fprintf(f2, "%s{ " DBQ(nameserver) ": " + DBQ(%s) " }", + first ? "" : ", ", token); + token = strtok(NULL, search_nl); + first= 0; + } + fprintf (f1, "\n"); + fprintf(f2, " ]\n"); + + fclose(f); + fclose(f1); + fclose(f2); + + do_rm_dns_static_info= 0; + } + else if( strncmp(line,"FIRMWARE_KERNEL ", 16)==0 ) + { + } + bzero( line, ATLAS_BUF_SIZE ); + fgets( line, MAX_READ, read_from ); + l++; + } + if(do_rm_v4_static_info) + { + // delete the static configuration + unlink(atlas_netconfig_v4); + unlink(atlas_network_v4_static_info); + unlink(atlas_network_v4_static_info_json); + } + if(do_rm_v6_static_info) + { + // delete the static configuration + unlink(atlas_netconfig_v6); + unlink(atlas_network_v6_static_info); + unlink(atlas_network_v6_static_info_json); + } + if (do_rm_dns_static_info) + { + unlink(atlas_network_dns_static_info); + unlink(atlas_network_dns_static_info_json); + } + } + else if (strncmp(line,"WAIT\n",5) == 0 ) + { + read_wait(read_from, "REG_WAIT_UNTIL", ATLAS_WAIT ); + + } + else { + char *p = strchr(line,'\n'); + if( p!=NULL ) *p = '\0'; + atlas_log( ERROR, "OK expected, got \"%s\" instead\n", line ); + read_wait(read_from, "REG_WAIT_UNTIL", ATLAS_DEFAULT_WAIT); /* we got error the only action from probe is wait. so force it*/ + ret = 1; + } + return ret; +} + + +void atlas_log( int level UNUSED_PARAM, const char *msg UNUSED_PARAM, ... ) +{ +/* + if( atlas_log_level<=level ) + { + va_list arg; + va_start ( arg, msg ); + + FILE *lf = fopen( atlas_log_file, "at" ); + if( lf==NULL ) + return; // not much we can do + + fprintf( lf, "%d\t%d\t", (int)time(NULL), level ); + vfprintf( lf, msg, arg ); + fclose(lf); + + va_end( arg ); + } +*/ +} diff --git a/networking/rptaddrs.c b/networking/rptaddrs.c new file mode 100644 index 0000000..1115559 --- /dev/null +++ b/networking/rptaddrs.c @@ -0,0 +1,775 @@ +/* + * rptaddrs.c + * Copyright (c) 2013 RIPE NCC <atlas@ripe.net> + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include <errno.h> +#include <resolv.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <net/route.h> +#include <net/if.h> +#include <inet_common.h> +#include "../eperd/eperd.h" +#include "../eperd/readresolv.h" + +#include "libbb.h" + +#define IPV4_ROUTE_FILE "/proc/net/route" +#define IF_INET6_FILE "/proc/net/if_inet6" +#define IPV6_ROUTE_FILE "/proc/net/ipv6_route" +#define SUFFIX ".new" + +#define IPV4_STATIC ATLAS_STATUS "/network_v4_static_info.json" +#define IPV6_STATIC ATLAS_STATUS "/network_v6_static_info.json" +#define DNS_STATIC ATLAS_STATUS "/network_dns_static_info.json" +#define NETWORK_INFO ATLAS_STATUS "/network_info.txt" + +#define SAFE_PREFIX_N ATLAS_DATA_NEW + +#define OPT_STRING "A:O:c:" + +#define DBQ(str) "\"" #str "\"" +#define JS(key, val) fprintf(fh, "\"" #key"\" : \"%s\" , ", val); +#define JS1(key, fmt, val) fprintf(fh, "\"" #key"\" : "#fmt" , ", val); + +#ifndef IPV6_MASK +#define IPV6_MASK (RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE) +#endif + +#define IPV6_ADDR_LOOPBACK 0x0010U +#define IPV6_ADDR_LINKLOCAL 0x0020U +#define IPV6_ADDR_SITELOCAL 0x0040U + +#define IPV6_ADDR_COMPATv4 0x0080U + +#define IPV6_ADDR_SCOPE_MASK 0x00f0U + +enum { + OPT_a = (1 << 0), +}; + +static FILE *setup_cache(char *cache_name); +static int setup_ipv4_rpt(FILE *of); +static int setup_dhcpv4(FILE *of); +static int setup_ipv6_rpt(FILE *of); +static int setup_dns(FILE *of); +static int setup_static_rpt(FILE *of); +static int report_line(FILE *of, const char *fn); +static int check_cache(char *cache_name); +static int rpt_ipv6(char *cache_name, char *out_name, char *opt_atlas, int opt_append); +static void report(const char *fmt, ...); +static void report_err(const char *fmt, ...); + +int rptaddrs_main(int argc, char *argv[]) +{ + int r, need_report; + unsigned opt; + char *opt_atlas; + char *cache_name; /* temp file in an intermediate format */ + char *out_name; /* output file in json: timestamp opt_atlas */ + int opt_append; + FILE *cf; + + opt_atlas= NULL; + out_name = NULL; + cache_name = NULL; + opt_atlas = NULL; + opt_complementary= NULL; + opt_append = FALSE; + + opt= getopt32(argv, OPT_STRING, &opt_atlas, &out_name, &cache_name); + + if (out_name && !validate_filename(out_name, SAFE_PREFIX_N)) + { + crondlog(LVL8 "insecure file '%s' : allowed '%s'", out_name, + SAFE_PREFIX_N); + return 1; + } + if (cache_name && !validate_filename(cache_name, SAFE_PREFIX_N)) + { + crondlog(LVL8 "insecure file '%s' allowed %s", cache_name, + SAFE_PREFIX_N); + return 1; + } + + if (!cache_name) { + crondlog(LVL8 "missing requried option, -c <cache_file>"); + return 1; + } + + if (opt & OPT_a) + opt_append = TRUE; + + cf= setup_cache(cache_name); + if (cf == NULL) + return 1; + + r= setup_ipv4_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_dhcpv4(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_ipv6_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_dns(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + + r= setup_static_rpt(cf); + if (r == -1) + { + fclose(cf); + return 1; + } + fclose(cf); + + need_report= check_cache(cache_name); + if (need_report) + { + r = rpt_ipv6(cache_name, out_name, opt_atlas, opt_append); + if (r != 0) + return r; + } + + return 0; +} + +static FILE *setup_cache(char *cache_name) +{ + FILE *out_file; + char filename[80]; + + if (strlen(cache_name) + strlen(SUFFIX) + 1 > sizeof(filename)) + { + report("cache name '%s' too long", cache_name); + return NULL; + } + + strlcpy(filename, cache_name, sizeof(filename)); + strlcat(filename, SUFFIX, sizeof(filename)); + + out_file= fopen(filename, "w"); + if (out_file == NULL) + { + report_err("unable to create '%s'", filename); + return NULL; + } + + return out_file; +} + +#define MAX_INF 10 + +static int setup_ipv4_rpt(FILE *of) +{ + int i, r, s, first; + unsigned dest, gateway, flags, refcnt, use, metric, mask; + FILE *in_file; + struct in_addr in_addr; + struct ifconf ifconf; + struct ifreq ifreq1; + struct ifreq ifreq[MAX_INF]; + char infname[20]; + char line[256]; + + s= socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (s == -1) + { + report_err("socket failed"); + return -1; + } + ifconf.ifc_len= sizeof(ifreq); + ifconf.ifc_req= ifreq; + r= ioctl(s, SIOCGIFCONF, &ifconf); + if (r == -1) + { + report_err("SIOCGIFCONF failed"); + close(s); + return -1; + } + + fprintf(of, DBQ(inet-addresses) ": [ "); + for (i= 0; i<ifconf.ifc_len/sizeof(ifreq[0]); i++) + { + memcpy(ifreq1.ifr_name, ifreq[i].ifr_name, + sizeof(ifreq1.ifr_name)); + r= ioctl(s, SIOCGIFNETMASK, &ifreq1); + if (r == -1) + { + report_err("SIOCGIFNETMASK failed"); + close(s); + return -1; + } + fprintf(of, "%s{ " DBQ(inet-addr) ": " DBQ(%s) ", ", + i == 0 ? "" : ", ", + inet_ntoa(((struct sockaddr_in *)(&ifreq[i].ifr_addr)) + ->sin_addr)); + fprintf(of, DBQ(netmask) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " }", + inet_ntoa(((struct sockaddr_in *)(&ifreq1.ifr_addr))-> + sin_addr), + ifreq[i].ifr_name); + } + + close(s); + + fprintf(of, " ]"); + + in_file= fopen(IPV4_ROUTE_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IPV4_ROUTE_FILE); + return -1; + } + + /* Skip first line */ + fgets(line, sizeof(line), in_file); + + fprintf(of, ", " DBQ(inet-routes) ": [ "); + first= 1; + + while (fgets(line, sizeof(line), in_file) != NULL) + { + sscanf(line, "%16s %x %x %x %d %d %d %x", + infname, &dest, &gateway, &flags, &refcnt, &use, + &metric, &mask); + in_addr.s_addr= dest; + fprintf(of, "%s{ " DBQ(destination) ": " DBQ(%s) ", ", + first ? "" : ", ", inet_ntoa(in_addr)); + in_addr.s_addr= mask; + fprintf(of, DBQ(netmask) ": " DBQ(%s) ", ", + inet_ntoa(in_addr)); + in_addr.s_addr= gateway; + fprintf(of, DBQ(next-hop) ": " DBQ(%s) ", " + DBQ(interface) ": " DBQ(%s) " }", + inet_ntoa(in_addr), infname); + first= 0; + } + + fprintf(of, " ]"); + + fclose(in_file); + + return 0; +} + +static int setup_dhcpv4(FILE *of) +{ + int found; + FILE *in_file; + char *value; + char line[128]; + + in_file= fopen(NETWORK_INFO, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", NETWORK_INFO); + return -1; + } + found= 0; + while (fgets(line, sizeof(line), in_file) != NULL) + { + if (strncmp(line, "DHCP ", 5) == 0) + { + value= NULL; + if (strncmp(line+5, "True", 4) == 0) + value= "true"; + else if (strncmp(line+5, "False", 5) == 0) + value= "false"; + if (value) + { + fprintf(of, ", " DBQ(inet-dhcp) ": %s", + value); + found= 1; + break; + } + } + } + + fclose(in_file); + if (found) + return 0; + report("setup_dhcpv4: DHCP field not found"); + return -1; +} + +static int setup_ipv6_rpt(FILE *of) +{ + int r, n; + char filename[80]; + char dst6in[INET6_ADDRSTRLEN]; + char nh6in[INET6_ADDRSTRLEN]; /* next hop */ + char *dst6out = NULL; + char *nh6out = NULL; + char dst6p[8][5]; + char nh6p[8][5]; + char iface[16], flags[16]; + char Scope[32]; + int scope, dad_status, if_idx; + int iflags, metric, refcnt, use, prefix_len, slen; + struct sockaddr_in6 sdst6, snh6; + char buf2[1024]; + + FILE *in_file; + + /* Copy IF_INET6_FILE */ + in_file= fopen(IF_INET6_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IF_INET6_FILE); + return -1; + } + n = 0; + while ((r = fscanf(in_file, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", + dst6p[0], dst6p[1], dst6p[2] + , dst6p[3], dst6p[4], dst6p[5] + , dst6p[6], dst6p[7], &if_idx, &prefix_len + , &scope, &dad_status, iface)) != EOF) { + + snprintf(dst6in, sizeof(dst6in), "%s:%s:%s:%s:%s:%s:%s:%s", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], + dst6p[4], dst6p[5], dst6p[6], dst6p[7]); + + inet_pton(AF_INET6, dst6in, (struct sockaddr *) &sdst6.sin6_addr); + sdst6.sin6_family = AF_INET6; + dst6out = INET6_rresolve((struct sockaddr_in6 *) &sdst6, 0x0fff); + + switch (scope & IPV6_ADDR_SCOPE_MASK) { + case 0: + snprintf(Scope, sizeof(Scope), "Global"); + break; + case IPV6_ADDR_LINKLOCAL: + snprintf(Scope, sizeof(Scope), "Link"); + break; + case IPV6_ADDR_SITELOCAL: + snprintf(Scope, sizeof(Scope), "Site"); + break; + case IPV6_ADDR_COMPATv4: + snprintf(Scope, sizeof(Scope), "Compat"); + break; + case IPV6_ADDR_LOOPBACK: + snprintf(Scope, sizeof(Scope), "Host"); + break; + default: + snprintf(Scope, sizeof(Scope), "Unknown %d", scope); + } + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(inet6-addr) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(scope) " : " DBQ(%s) ", " DBQ(interface) + " : " DBQ(%s) "}", + n ? "" : ", \"inet6-addresses\" : [", n ? ", " : "" + , dst6out, prefix_len, Scope, iface); + + /* printf("%s\n", buf2); */ + + if(dst6out) { + free(dst6out); + dst6out=NULL; + } + n++; + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + if (ferror(in_file)) + { + report_err("error reading from '%s'", IF_INET6_FILE); + fclose(in_file); + return -1; + } + } + if ( n > 0 ) { + r = snprintf(buf2, 2, "]"); + } + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + fclose(in_file); + + /* Copy IPV6_ROUTE_FILE */ + in_file= fopen(IPV6_ROUTE_FILE, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", IPV6_ROUTE_FILE); + return -1; + } + + n = 0; + while ((r = fscanf (in_file, "%4s%4s%4s%4s%4s%4s%4s%4s%x%*s%x%4s%4s%4s%4s%4s%4s%4s%4s%x%x%x%x%s\n", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], dst6p[4], + dst6p[5], dst6p[6], dst6p[7], &prefix_len, &slen, + nh6p[0], nh6p[1], nh6p[2], nh6p[3], nh6p[4], + nh6p[5], nh6p[6], nh6p[7], &metric, &use, &refcnt, &iflags, iface)) != EOF) { + + if (r != 23) { + if ((r < 0) && feof(in_file)) { /* EOF with no (nonspace) chars read. */ + break; + } + report_err("reading '%s'", IF_INET6_FILE); + fclose(in_file); + return -1; + } + + /* skip some the stuff we don't want to report */ + if (!(iflags & RTF_UP)) { /* Skip interfaces that are down. */ + continue; + } + if ((iflags & RTF_ADDRCONF) && (iflags & RTF_CACHE)) { /* Skip interfaces that are down. */ + continue; + } + + if ( strncmp (dst6p[0], "ff02", strlen("ff02")) == 0 ) { + continue; + } + if ( strncmp (dst6p[0], "ff00", strlen("ff00")) == 0 ) { + continue; + } + + snprintf(dst6in, sizeof(dst6in), "%s:%s:%s:%s:%s:%s:%s:%s", + dst6p[0], dst6p[1], dst6p[2], dst6p[3], + dst6p[4], dst6p[5], dst6p[6], dst6p[7]); + + snprintf(nh6in, sizeof(nh6in), "%s:%s:%s:%s:%s:%s:%s:%s", + nh6p[0], nh6p[1], nh6p[2], nh6p[3], + nh6p[4], nh6p[5], nh6p[6], nh6p[7]); + + + set_flags(flags, (iflags & IPV6_MASK)); + inet_pton(AF_INET6, dst6in, (struct sockaddr *) &sdst6.sin6_addr); + sdst6.sin6_family = AF_INET6; + dst6out = INET6_rresolve((struct sockaddr_in6 *) &sdst6, 0x0fff); + + inet_pton(AF_INET6, nh6in, (struct sockaddr *) &snh6.sin6_addr); + snh6.sin6_family = AF_INET6; + nh6out = INET6_rresolve((struct sockaddr_in6 *) &snh6, 0x0fff); + + + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(destination) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(next-hop) " : " DBQ(%s) ", " DBQ(flags) + " : " DBQ(%s) ", " DBQ(metric) " : %d , " + DBQ(interface) " : " DBQ(%s) "}", + n ? "" : ", \"inet6-routes\" : [", n ? ", " : "" + , dst6out, prefix_len, nh6out, flags, metric + , iface); + + /* + r = snprintf(buf2, sizeof(buf2), "%s %s{" DBQ(destination) " : " + DBQ(%s) ", " DBQ(prefix-length) " : %d," + DBQ(next-hop) " : " DBQ(%s) ", " DBQ(flags) + " : " DBQ(%s) ", " DBQ(metric) " : %d , " + DBQ(interface) " : " DBQ(%s) "}", + n ? " " : '"inet6-routes" [' + , n ? ", " : "" + , dst6out, prefix_len, nh6out, flags, metric + , iface); + */ + + /* printf("%s\n", buf2); */ + + if(dst6out) { + free(dst6out); + dst6out=NULL; + } + if(nh6out) { + free(nh6out); + nh6out=NULL; + } + + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + n++; + } + if ( n > 0 ) { + r = snprintf(buf2, 2, "]"); + } + if (fwrite(buf2, 1, r, of) != r) + { + report_err("error writing to '%s'", filename); + fclose(in_file); + return -1; + } + + + if (ferror(in_file)) + { + report_err("error reading from '%s'", IPV6_ROUTE_FILE); + fclose(in_file); + return -1; + } + fclose(in_file); + + return 0; +} + +static int setup_dns(FILE *of) +{ + int i, resolv_max; + char nslist[MAXNS][INET6_ADDRSTRLEN * 2]; + + resolv_max= 0; + + get_local_resolvers_nocache(nslist, &resolv_max); + + fprintf(of, ", " DBQ(dns) ": [ "); + for (i= 0; i<resolv_max; i++) + { + fprintf(of, "%s{ " DBQ(nameserver) ": " DBQ(%s) " }", + i == 0 ? "" : ", ", + nslist[i]); + } + + fprintf(of, " ]"); + + return 0; +} + +static int setup_static_rpt(FILE *of) +{ + int r; + + r= report_line(of, IPV4_STATIC); + if (r == -1) + return -1; + r= report_line(of, IPV6_STATIC); + if (r == -1) + return -1; + r= report_line(of, DNS_STATIC); + if (r == -1) + return -1; + return 0; +} + +static int report_line(FILE *of, const char *fn) +{ + FILE *f; + char *nl; + char line[256]; + + f= fopen(fn, "r"); + if (f == NULL) + { + if (errno != ENOENT) + { + report_err("open '%s' failed", fn); + return -1; + } + } + else + { + if (fgets(line, sizeof(line), f) == NULL) + { + if (ferror(f)) + { + report_err("error reading from '%s'", fn); + } + else + report("error reading from '%s': EOF"); + fclose(f); + return -1; + } + fclose(f); + nl= strchr(line, '\n'); + if (nl == NULL) + { + report("line too long in '%s'", fn); + return -1; + } + *nl= '\0'; + fprintf(of, ", %s", line); + } + + return 0; +} + +static int check_cache(char *cache_name) +{ + int r, need_report; + char filename[80]; + + char buf1[1024]; + char buf2[1024]; + FILE *in_file, *cache_file; + + strlcpy(filename, cache_name, sizeof(filename)); + strlcat(filename, SUFFIX, sizeof(filename)); + + need_report= 0; + + /* Now check if the new file is different from the cache one */ + cache_file= fopen(cache_name, "r"); + if (cache_file == NULL) + { + /* Assume that any kind of error here calls for reporting */ + need_report= 1; + } + + if (cache_file) + { + in_file= fopen(filename, "r"); + if (in_file == NULL) + { + report_err("unable to open '%s'", filename); + fclose(cache_file); + return 1; + } + + /* Compare them */ + while (r= fread(buf1, 1, sizeof(buf1), cache_file), r > 0) + { + if (fread(buf2, 1, sizeof(buf2), in_file) != r) + { + /* Ignore errors, just report */ + need_report= 1; + break; + } + + if (memcmp(buf1, buf2, r) != 0) + { + /* Something changed, report */ + need_report= 1; + break; + } + } + + /* Maybe something got added */ + if (!need_report) + { + if (fread(buf2, 1, sizeof(buf2), in_file) != 0) + { + need_report= 1; + } + } + fclose(cache_file); + fclose(in_file); + } + + if (need_report) + { + if (rename(filename, cache_name) == -1) + { + report_err("renaming '%s' to '%s' failed", + filename, cache_name); + return 0; + } + } + else + { + if (unlink(filename) == -1) + { + report_err("unlinking '%s' failed", + filename); + } + } + + return need_report; +} + +static int rpt_ipv6(char *cache_name, char *out_name, char *opt_atlas, int opt_append) +{ + FILE *file; + FILE *fh; + char buf[256]; + struct timeval now; + + file= fopen(cache_name, "r"); + if (!file) + { + report_err("unable to open cache file '%s'", cache_name); + return 1; + } + + if (out_name) { + if(opt_append) + fh= fopen(out_name, "a"); + else + fh= fopen(out_name, "w"); + + if (!fh) + { + report_err("unable to append to '%s'", out_name); + return 1; + } + } + else + fh = stdout; + + fprintf(fh, "RESULT { "); + if(opt_atlas) + { + JS(id, opt_atlas); + } + gettimeofday(&now, NULL); + JS1(time, %ld, now.tv_sec); + + /* Copy all lines */ + while (fgets(buf, sizeof(buf), file) != NULL) + { + fputs(buf, fh); + } + fprintf(fh, "}\n"); + fclose(file); + fclose(fh); + + return 0; +} + +static void report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + fprintf(stderr, "rptaddrs: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +static void report_err(const char *fmt, ...) +{ + int t_errno; + va_list ap; + + t_errno= errno; + + va_start(ap, fmt); + + fprintf(stderr, "rptaddrs: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(t_errno)); + + va_end(ap); +} diff --git a/networking/rptra6.c b/networking/rptra6.c index 8b45e72..b481252 100644 --- a/networking/rptra6.c +++ b/networking/rptra6.c @@ -35,7 +35,7 @@ static void usage(void) exit(1); } -int rptaddr6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; +int rptra6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; int rptra6_main(int argc, char *argv[]) { int i, r, first, sock, on, nrecv, rcvd_ttl, olen; |