void netstart (void) { char buffer[20]; /* input buffer */ int32 nchars; /* number Of characters read */ int32 i; /* counter from 0 to nchars */ bool8 found; /* was a valid answer found? */ char ch; /* one character from the buff. */ struct ifentry *ifptr; /* ptr to interface */ uint32 ipaddr; /* IP address on interface 0 */ uint32 suffix; /* host suffix to use on both */ /* othernet interfaces */ static uint32 rarindex = 1; /* next RAR index to use */ struct ether *ethptr; /* ptr to Ethernet control blk. */ char *ifnames[] = {"Lab Ethernet","Othernet 1","Othernet 2"}; /* Initialize network interfaces */ kprintf("...initializing network stack\n"); net_init(); /* Initialize NAT tables */ nat_init(); /* Delay because Ethernet driver doesn't work without it */ sleepms(800); /* Force system to use DHCP to obtain an address */ kprintf("...using dhcp to obtain an IP address\n"); ipaddr = getlocalip(); if (ipaddr == SYSERR) { panic("Error: could not obtain an IP address\n\r"); } kprintf("\nIP address is %d.%d.%d.%d (0x%08x)\n\r", (ipaddr>>24)&0xff, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff,ipaddr); ifptr = &if_tab[0]; kprintf("Subnet mask is %d.%d.%d.%d and router is %d.%d.%d.%d\n\r", (ifptr->if_ipmask>>24)&0xff, (ifptr->if_ipmask>>16)&0xff, (ifptr->if_ipmask>> 8)&0xff, ifptr->if_ipmask&0xff, (ifptr->if_iprouter>>24)&0xff, (ifptr->if_iprouter>>16)&0xff, (ifptr->if_iprouter>> 8)&0xff, ifptr->if_iprouter&0xff); /* Ask the user for a Bing ID */ found = FALSE; while (!found) { printf("\n\rEnter a bing ID between 0 and 255: "); nchars = read(CONSOLE, buffer, 20); if ((nchars == SYSERR) || (nchars == EOF) || (nchars < 2)) { continue; } nchars--; /* Eliminate NEWLINE */ bingid = 0; for (i=0; i<nchars; i++) { ch = buffer[i]; if ( (ch<'0') || (ch>'9')) { break; } bingid = 10*bingid + (ch-'0'); } if ((i<nchars) || (bingid > 254)) { continue; } found = TRUE; } printf("Bing ID is set to %d.\n", bingid); /* Generate Othernet emulation addresses */ suffix = ipaddr & 0x0000ffff; /* suffix is last two bytes of */ /* the IP address */ ethptr = ðertab[0]; /* Othernet 1 */ ifptr = &if_tab[1]; ifptr->if_ipmask = 0xffff0000; /* 255.255.0.0. */ ifptr->if_ipprefix= 0x0a010000; /* 10.1.0.0/16 */ ifptr->if_ipucast = ifptr->if_ipprefix | suffix; ifptr->if_ipbcast = ifptr->if_ipprefix | ~ifptr->if_ipmask; ifptr->if_macucast[0] = 0x11; ifptr->if_macucast[1] = 0xff & (ipaddr >> 24); ifptr->if_macucast[2] = 0xff & (ipaddr >> 16); ifptr->if_macucast[3] = 0xff & (ipaddr >> 8); ifptr->if_macucast[4] = 0xff & (ipaddr >> 0); ifptr->if_macucast[5] = 0xff & bingid; e1000e_rar_set(ethptr, ifptr->if_macucast, rarindex++); ifptr->if_macbcast[0] = 0x11; ifptr->if_macbcast[1] = 0xff; ifptr->if_macbcast[2] = 0xff; ifptr->if_macbcast[3] = 0xff; ifptr->if_macbcast[4] = 0xff; ifptr->if_macbcast[5] = 0xff & bingid; e1000e_rar_set(ethptr, ifptr->if_macbcast, rarindex++); ifptr->if_ipvalid = TRUE; /* Othernet 2 */ ifptr = &if_tab[2]; ifptr->if_ipmask = 0xffff0000; /* 255.255.0.0. */ ifptr->if_ipprefix= 0x0a020000; /* 10.2.0.0/16 */ ifptr->if_ipucast = ifptr->if_ipprefix | suffix; ifptr->if_ipbcast = ifptr->if_ipprefix | ~ifptr->if_ipmask; ifptr->if_macucast[0] = 0x21; ifptr->if_macucast[1] = 0xff & (ipaddr >> 24); ifptr->if_macucast[2] = 0xff & (ipaddr >> 16); ifptr->if_macucast[3] = 0xff & (ipaddr >> 8); ifptr->if_macucast[4] = 0xff & (ipaddr >> 0); ifptr->if_macucast[5] = 0xff & bingid; e1000e_rar_set(ethptr, ifptr->if_macucast, rarindex++); ifptr->if_macbcast[0] = 0x21; ifptr->if_macbcast[1] = 0xff; ifptr->if_macbcast[2] = 0xff; ifptr->if_macbcast[3] = 0xff; ifptr->if_macbcast[4] = 0xff; ifptr->if_macbcast[5] = 0xff & bingid; e1000e_rar_set(ethptr, ifptr->if_macbcast, rarindex++); ifptr->if_ipvalid = TRUE; /* Ask the user what to run */ found = FALSE; while (!found) { printf("\nEnter r for router or hX for host on interface X: "); nchars = read(CONSOLE, buffer, 20); switch (nchars) { case 2: ch = buffer[0]; if ( (ch!='r') && (ch!='R')) { continue; } host = FALSE; ifprime = 0; found = TRUE; break; case 3: ch = buffer[0]; if ((ch!='h') && (ch!='H')) { continue; } ch = buffer[1]; if ( (ch<'0') || (ch>'2')) { continue; } ifprime = ch - '0'; host = TRUE; found = TRUE; break; default: continue; } } if (host) { printf("\nRunning host on %s\n\r", ifnames[ifprime]); if (ifprime != 0) { /* Shut off Ethernet and bring up other net */ if_tab[0].if_state = IF_DOWN; ifptr = &if_tab[ifprime]; ifptr->if_state = IF_UP; /* Set default route to router address */ if (ifptr->if_iprouter == 0) { ifptr->if_iprouter = ifptr->if_ipprefix | ROUTER_SUFFIX; } } } else { kprintf("Running a router\n\r"); for (i=0; i<NIFACES; i++) { ifptr = &if_tab[i]; ifptr->if_state = IF_UP; if (i != 0) { /* Set router address */ ifptr->if_ipucast = ifptr->if_ipprefix | ROUTER_SUFFIX; } } } return; }
/* * Main entry point. */ int main(int argc, char *argv[]) { const char *argv0; int ch; opts_t *opts; char *natengine; int pidfd = -1; int rv = EXIT_FAILURE; argv0 = argv[0]; opts = opts_new(); natengine = strdup(nat_getdefaultname()); while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z "k:c:C:K:t:OPs:e:Eu:j:p:l:L:S:dDVh")) != -1) { switch (ch) { case 'c': if (opts->cacrt) X509_free(opts->cacrt); opts->cacrt = ssl_x509_load(optarg); if (!opts->cacrt) { fprintf(stderr, "%s: error loading CA " "cert from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } ssl_x509_refcount_inc(opts->cacrt); sk_X509_insert(opts->chain, opts->cacrt, 0); if (!opts->cakey) { opts->cakey = ssl_key_load(optarg); } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 'k': if (opts->cakey) EVP_PKEY_free(opts->cakey); opts->cakey = ssl_key_load(optarg); if (!opts->cakey) { fprintf(stderr, "%s: error loading CA " "key from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } if (!opts->cacrt) { opts->cacrt = ssl_x509_load(optarg); if (opts->cacrt) { ssl_x509_refcount_inc( opts->cacrt); sk_X509_insert(opts->chain, opts->cacrt, 0); } } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 'C': if (ssl_x509chain_load(NULL, &opts->chain, optarg) == -1) { fprintf(stderr, "%s: error loading " "chain from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } break; case 'K': if (opts->key) EVP_PKEY_free(opts->key); opts->key = ssl_key_load(optarg); if (!opts->key) { fprintf(stderr, "%s: error loading lea" "f key from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 't': if (!sys_isdir(optarg)) { fprintf(stderr, "%s: '%s' is not a " "directory\n", argv0, optarg); exit(EXIT_FAILURE); } if (opts->tgcrtdir) free(opts->tgcrtdir); opts->tgcrtdir = strdup(optarg); break; case 'O': opts->deny_ocsp = 1; break; case 'P': opts->passthrough = 1; break; #ifndef OPENSSL_NO_DH case 'g': if (opts->dh) DH_free(opts->dh); opts->dh = ssl_dh_load(optarg); if (!opts->dh) { fprintf(stderr, "%s: error loading DH " "params from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } break; #endif /* !OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH case 'G': { EC_KEY *ec; if (opts->ecdhcurve) free(opts->ecdhcurve); if (!(ec = ssl_ec_by_name(optarg))) { fprintf(stderr, "%s: unknown curve " "'%s'\n", argv0, optarg); exit(EXIT_FAILURE); } EC_KEY_free(ec); opts->ecdhcurve = strdup(optarg); break; } #endif /* !OPENSSL_NO_ECDH */ #ifdef SSL_OP_NO_COMPRESSION case 'Z': opts->sslcomp = 0; break; #endif /* SSL_OP_NO_COMPRESSION */ case 's': if (opts->ciphers) free(opts->ciphers); opts->ciphers = strdup(optarg); break; case 'e': free(natengine); natengine = strdup(optarg); break; case 'E': nat_list_engines(); exit(EXIT_SUCCESS); break; case 'u': if (opts->dropuser) free(opts->dropuser); opts->dropuser = strdup(optarg); break; case 'p': if (opts->pidfile) free(opts->pidfile); opts->pidfile = strdup(optarg); break; case 'j': if (opts->jaildir) free(opts->jaildir); opts->jaildir = strdup(optarg); break; case 'l': if (opts->connectlog) free(opts->connectlog); opts->connectlog = strdup(optarg); break; case 'L': if (opts->contentlog) free(opts->contentlog); opts->contentlog = strdup(optarg); opts->contentlogdir = 0; break; case 'S': if (opts->contentlog) free(opts->contentlog); opts->contentlog = strdup(optarg); opts->contentlogdir = 1; break; case 'd': opts->detach = 1; break; case 'D': log_dbg_mode(LOG_DBG_MODE_ERRLOG); opts->debug = 1; break; case 'V': main_version(); exit(EXIT_SUCCESS); case 'h': main_usage(); exit(EXIT_SUCCESS); case '?': exit(EXIT_FAILURE); default: main_usage(); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; opts->spec = proxyspec_parse(&argc, &argv, natengine); /* usage checks */ if (opts->detach && OPTS_DEBUG(opts)) { fprintf(stderr, "%s: -d and -D are mutually exclusive.\n", argv0); exit(EXIT_FAILURE); } if (!opts->spec) { fprintf(stderr, "%s: no proxyspec specified.\n", argv0); exit(EXIT_FAILURE); } for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) { if (spec->connect_addrlen || spec->sni_port) continue; if (!spec->natengine) { fprintf(stderr, "%s: no supported NAT engines " "on this platform.\n" "Only static addr and SNI proxyspecs " "supported.\n", argv0); exit(EXIT_FAILURE); } if (spec->listen_addr.ss_family == AF_INET6 && !nat_ipv6ready(spec->natengine)) { fprintf(stderr, "%s: IPv6 not supported by '%s'\n", argv0, spec->natengine); exit(EXIT_FAILURE); } spec->natlookup = nat_getlookupcb(spec->natengine); spec->natsocket = nat_getsocketcb(spec->natengine); } if (opts_has_ssl_spec(opts)) { if ((opts->cacrt || !opts->tgcrtdir) && !opts->cakey) { fprintf(stderr, "%s: no CA key specified (-k).\n", argv0); exit(EXIT_FAILURE); } if (opts->cakey && !opts->cacrt) { fprintf(stderr, "%s: no CA cert specified (-c).\n", argv0); exit(EXIT_FAILURE); } if (opts->cakey && opts->cacrt && (X509_check_private_key(opts->cacrt, opts->cakey) != 1)) { fprintf(stderr, "%s: CA cert does not match key.\n", argv0); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } } /* prevent multiple instances running */ if (opts->pidfile) { pidfd = sys_pidf_open(opts->pidfile); if (pidfd == -1) { fprintf(stderr, "%s: cannot open PID file '%s' " "- process already running?\n", argv0, opts->pidfile); exit(EXIT_FAILURE); } } /* dynamic defaults */ if (!opts->ciphers) { opts->ciphers = strdup("ALL:-aNULL"); if (!opts->ciphers) { fprintf(stderr, "%s: out of memory.\n", argv0); exit(EXIT_FAILURE); } } if (!opts->jaildir && (geteuid() == 0) && !opts->contentlogdir) { opts->jaildir = strdup("/var/empty"); } if (!opts->dropuser && !geteuid() && !getuid() && !opts->contentlogdir) { opts->dropuser = strdup("nobody"); } if (opts_has_ssl_spec(opts) && !opts->key) { opts->key = ssl_key_genrsa(1024); if (!opts->key) { fprintf(stderr, "%s: error generating RSA key:\n", argv0); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } if (OPTS_DEBUG(opts)) { log_dbg_printf("Generated RSA key for leaf certs.\n"); } } /* debugging */ if (OPTS_DEBUG(opts)) { main_version(); log_dbg_printf("proxyspecs:\n"); for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) { char *lbuf, *cbuf = NULL; lbuf = sys_sockaddr_str((struct sockaddr *) &spec->listen_addr, spec->listen_addrlen); if (spec->connect_addrlen) { cbuf = sys_sockaddr_str((struct sockaddr *) &spec->connect_addr, spec->connect_addrlen); } if (spec->sni_port) { asprintf(&cbuf, "sni %i", spec->sni_port); } log_dbg_printf("- %s %s %s %s\n", lbuf, (spec->ssl ? "ssl" : "tcp"), (spec->http ? "http" : "plain"), (spec->natengine ? spec->natengine : cbuf)); if (lbuf) free(lbuf); if (cbuf) free(cbuf); } if (opts->cacrt) { char *subj = ssl_x509_subject(opts->cacrt); log_dbg_printf("Loaded CA: '%s'\n", subj); free(subj); #ifdef DEBUG_CERTIFICATE log_dbg_print_free(ssl_x509_to_str(opts->cacrt)); log_dbg_print_free(ssl_x509_to_pem(opts->cacrt)); #endif /* DEBUG_CERTIFICATE */ } else { log_dbg_printf("No CA loaded.\n"); } } /* * Initialize as much as possible before daemon() in order to be * able to provide direct feedback to the user when failing. */ if (cachemgr_preinit() == -1) { fprintf(stderr, "%s: failed to preinit cachemgr.\n", argv0); exit(EXIT_FAILURE); } if (log_preinit(opts) == -1) { fprintf(stderr, "%s: failed to preinit logging.\n", argv0); exit(EXIT_FAILURE); } if (nat_preinit() == -1) { fprintf(stderr, "%s: failed to preinit NAT lookup.\n", argv0); exit(EXIT_FAILURE); } /* Bind listeners before dropping privileges */ proxy_ctx_t *proxy = proxy_new(opts); if (!proxy) { fprintf(stderr, "%s: failed to initialize proxy.\n", argv0); exit(EXIT_FAILURE); } /* Drop privs, chroot, detach from TTY */ if (sys_privdrop(opts->dropuser, opts->jaildir) == -1) { fprintf(stderr, "%s: failed to drop privileges: %s\n", argv0, strerror(errno)); exit(EXIT_FAILURE); } if (opts->detach) { if (OPTS_DEBUG(opts)) { log_dbg_printf("Detaching from TTY, see syslog for " "errors after this point\n"); } if (daemon(1, 0) == -1) { fprintf(stderr, "%s: failed to detach from TTY: %s\n", argv0, strerror(errno)); exit(EXIT_FAILURE); } log_err_mode(LOG_ERR_MODE_SYSLOG); ssl_reinit(); } /* Post-privdrop/chroot/detach initialization, thread spawning */ if (log_init(opts) == -1) { fprintf(stderr, "%s: failed to init log facility.\n", argv0); goto out_log_failed; } if (opts->pidfile && (sys_pidf_write(pidfd) == -1)) { log_err_printf("Failed to write PID to PID file '%s': %s\n", opts->pidfile, strerror(errno)); goto out_pidwrite_failed; } if (cachemgr_init() == -1) { log_err_printf("Failed to init cache manager.\n"); goto out_cachemgr_failed; } if (nat_init() == -1) { log_err_printf("Failed to init NAT state table lookup.\n"); goto out_nat_failed; } if (opts->tgcrtdir) { sys_dir_eachfile(opts->tgcrtdir, main_loadtgcrt, opts); } rv = EXIT_SUCCESS; proxy_run(proxy); proxy_free(proxy); nat_fini(); out_nat_failed: cachemgr_fini(); out_cachemgr_failed: if (opts->pidfile) { sys_pidf_close(pidfd, opts->pidfile); } out_pidwrite_failed: log_fini(); out_log_failed: opts_free(opts); ssl_fini(); return rv; }
int main(int argc, char **argv) { struct packet_mreq pmr; struct ethtool_value ethtool; int sniff_sock; int length; char buffer[PACKET_BUFFER]; int i; time_t prevtime, curtime; log_info(PACKAGE_STRING " is starting"); /* initialize the socket for sniffing */ if ((sniff_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) { log_error("Unable to create listening socket"); return 1; } /* get the interface */ strncpy(interface.ifr_name, INTERFACE, IFNAMSIZ); if (ioctl(sniff_sock, SIOCGIFINDEX, &interface) == -1) { log_error("Unable to get the interface"); return 1; } /* get interface's HW address (i.e. MAC) */ if (ioctl(sniff_sock, SIOCGIFHWADDR, &interface) == 0) { memcpy(&mac, &interface.ifr_hwaddr.sa_data, sizeof(struct s_mac_addr)); /* disable generic segmentation offload */ ethtool.cmd = ETHTOOL_SGSO; ethtool.data = 0; interface.ifr_data = (caddr_t) ðtool; if (ioctl(sniff_sock, SIOCETHTOOL, &interface) == -1) { log_error("Unable to disable generic segmentation " "offload on the interface"); return 1; } /* reinitialize the interface */ interface.ifr_data = NULL; if (ioctl(sniff_sock, SIOCGIFINDEX, &interface) == -1) { log_error("Unable to reinitialize the interface"); return 1; } } else { log_error("Unable to get the interface's HW address"); return 1; } /* set the promiscuous mode */ memset(&pmr, 0x0, sizeof(pmr)); pmr.mr_ifindex = interface.ifr_ifindex; pmr.mr_type = PACKET_MR_PROMISC; if (setsockopt(sniff_sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (char *) &pmr, sizeof(pmr)) == -1) { log_error("Unable to set the promiscuous mode on the " "interface"); return 1; } /* some preparations */ /* compute binary IPv6 address of NDP multicast */ inet_pton(AF_INET6, "ff02::1:ff00:0", &ndp_multicast_addr); /* compute binary IPv6 address of WrapSix prefix */ inet_pton(AF_INET6, PREFIX, &wrapsix_ipv6_prefix); /* compute binary IPv4 address of WrapSix */ inet_pton(AF_INET, IPV4_ADDR, &wrapsix_ipv4_addr); /* compute binary IPv6 address of WrapSix host */ inet_pton(AF_INET6, HOST_IPV6_ADDR, &host_ipv6_addr); /* compute binary IPv4 address of WrapSix host */ inet_pton(AF_INET, HOST_IPV4_ADDR, &host_ipv4_addr); /* initiate sending socket */ if (transmission_init()) { log_error("Unable to initiate sending socket"); return 1; } /* initiate NAT tables */ nat_init(); /* initiate random numbers generator */ srand((unsigned int) time(NULL)); /* initialize time */ prevtime = time(NULL); /* sniff! :c) */ for (i = 1;; i++) { if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) == -1) { log_error("Unable to retrieve data from socket"); return 1; } process((char *) &buffer); if (i % 250000) { curtime = time(NULL); /* 2 seconds is minimum normal timeout */ if ((curtime - prevtime) >= 2) { nat_cleaning(); prevtime = curtime; } i = 0; } } /* clean-up */ /* close sending socket */ transmission_quit(); /* empty NAT tables */ nat_quit(); /* unset the promiscuous mode */ if (setsockopt(sniff_sock, SOL_PACKET, PACKET_DROP_MEMBERSHIP, (char *) &pmr, sizeof(pmr)) == -1) { log_error("Unable to unset the promiscuous mode on the " "interface"); /* do not call return here as we want to close the socket too */ } /* close the socket */ close(sniff_sock); return 0; }