#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootpc.h" #include "devices.h" #include "install.h" #include "log.h" #include "newt.h" #include "net.h" #include "perror.h" #include "windows.h" struct intfconfig_s { newtComponent ipLabel, nmLabel, gwLabel, nsLabel; newtComponent ipEntry, nmEntry, gwEntry, nsEntry; char * ip, * nm, * gw, * ns; char * bootpState; }; struct netconfig_s { newtComponent nsLabels[3], hnLabel, dnLabel; newtComponent nsEntrys[3], hnEntry, dnEntry; char * ns[3], * gw, * hn, * dn; }; static void ipCallback(newtComponent co, void * data); static void hnCallback(newtComponent co, void * data); /* It's a bit gross, but setupNetworkInterface() will setup your general networking information if bootp is used */ static int setupNetworkInterface(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl, int justConfig); static int doBringUpNetworking(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl, int justConfig); static int configureNetDevice(struct netInterface * intf); /* intf in configureNetwork is optional */ static int configureNetwork(struct netConfig * netc, struct netInterface * intf); static char * findAvailableNetDevice(void); static int doBootp(char * device, struct netInterface * intf, struct netConfig * netc) { struct netInterface minInterface; int rc; /* This is a bit of a hack, but it lets us use Jon Peatfield's bootp code w/o hacking at it. It's written to allow test mode to work as long as the runner sets the proper magic env variables. */ if (!testing) { logMessage("using bootp for device %s", device); minInterface.ip = minInterface.netmask = minInterface.network = 0; minInterface.broadcast = 0xffffffff; strcpy(minInterface.dev, device); if (configureNetDevice(&minInterface)) { logMessage("failed to setup minimal bootp interface %s", device); return 1; } winStatus(40, 3, "BOOTP", "Sending BOOTP request..."); rc = performBootp(device, "255.255.255.255", "", 10, 0, NULL, 0, 1, BP_PUT_ENV); newtPopWindow(); if (rc) { logMessage("performBootp() failed w/ return %d", rc); return 1; } } if (!getenv("BOOTP_IPADDR")) { errorWindow("bootp query did not return an IP address"); return 1; } /* These will be generated by bootpc.c even if they're not in the bootp reply */ inet_aton(getenv("BOOTP_IPADDR"), (struct in_addr *) &intf->ip); inet_aton(getenv("BOOTP_NETMASK"), (struct in_addr *) &intf->netmask); inet_aton(getenv("BOOTP_BROADCAST"), (struct in_addr *) &intf->broadcast); inet_aton(getenv("BOOTP_NETWORK"), (struct in_addr *) &intf->network); intf->useBootp = 1; intf->isConfigured = 1; strcpy(intf->dev, device); if (getenv("BOOTP_GATEWAYS_1")) { strcpy(netc->defaultGateway, getenv("BOOTP_GATEWAYS_1")); netc->isConfigured = 1; } if (getenv("BOOTP_DNSSRVS_1")) { netc->nameserver[0] = strdup(getenv("BOOTP_DNSSRVS_1")); netc->isConfigured = 1; if (getenv("BOOTP_DNSSRVS_2")) { netc->nameserver[1] = strdup(getenv("BOOTP_DNSSRVS_2")); if (getenv("BOOTP_DNSSRVS_3")) netc->nameserver[2] = strdup(getenv("BOOTP_DNSSRVS_3")); } } /* If bootp gave us a hostname and domain, use those. Otherwise, we'll try and query the nameserver a bit later on. If that fails as well, we'll try and use just the hostname BOOTP gave us. */ if (getenv("BOOTP_HOSTNAME") && getenv("BOOTP_DOMAIN")) { logMessage("bootp returned hostname and domain name"); strcpy(netc->hostname, getenv("BOOTP_HOSTNAME")); netc->isConfigured = 1; strcpy(netc->domainname, getenv("BOOTP_DOMAIN")); if (strcmp(netc->hostname, netc->domainname) && !strstr(netc->hostname, netc->domainname)) { strcat(netc->hostname, "."); strcat(netc->hostname, netc->domainname); } } return 0; } /* The interface/gateway needs to be configured before this will work! */ static int guessHostname(struct netInterface * intf, struct netConfig * netc) { struct in_addr addr; char ips[50]; if ((testing || intf->isUp) && netc->nameserver[0]) { logMessage("using nameserver to find host and domain name"); writeResolvConf("/etc", netc); memcpy(&addr, &intf->ip, sizeof(addr)); strcpy(ips, inet_ntoa(addr)); winStatus(40, 3, "Hostname", "Determing host name and domain..."); if (in2host(ips, BP_PUT_ENV)) { newtPopWindow(); logMessage("reverse name lookup failed"); if (getenv("BOOTP_HOSTNAME")) { strcpy(netc->hostname, getenv("BOOTP_HOSTNAME")); } return 1; } else { newtPopWindow(); logMessage("reverse name lookup worked"); strcpy(netc->hostname, getenv("BOOTP_HOSTFULL")); strcpy(netc->domainname, getenv("BOOTP_HOSTDOMAIN")); return 0; } } return 1; } int addDefaultRoute(struct netConfig netc) { int s; struct rtentry route; struct sockaddr_in addr; if (testing) return 0; if (!strlen(netc.defaultGateway)) return 0; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { close(s); errorWindow("socket: %s"); return 1; } memset(&route, 0, sizeof(route)); addr.sin_family = AF_INET; addr.sin_port = 0; inet_aton(netc.defaultGateway, &addr.sin_addr); memcpy(&route.rt_gateway, &addr, sizeof(addr)); addr.sin_addr.s_addr = INADDR_ANY; memcpy(&route.rt_dst, &addr, sizeof(addr)); memcpy(&route.rt_genmask, &addr, sizeof(addr)); route.rt_flags = RTF_UP | RTF_GATEWAY; route.rt_metric = 0; if (ioctl(s, SIOCADDRT, &route)) { close(s); errorWindow("SIOCADDRT: %s"); return 1; } return 0; } static int configureNetDevice(struct netInterface * intf) { struct ifreq req; struct rtentry route; int s; struct sockaddr_in addr; struct in_addr ia; char ip[20], nm[20], nw[20], bc[20]; addr.sin_family = AF_INET; addr.sin_port = 0; memcpy(&ia, &intf->ip, sizeof(intf->ip)); strcpy(ip, inet_ntoa(ia)); memcpy(&ia, &intf->netmask, sizeof(intf->netmask)); strcpy(nm, inet_ntoa(ia)); memcpy(&ia, &intf->broadcast, sizeof(intf->broadcast)); strcpy(bc, inet_ntoa(ia)); memcpy(&ia, &intf->network, sizeof(intf->network)); strcpy(nw, inet_ntoa(ia)); logMessage("configuring %s ip: %s nm: %s nw: %s bc: %s", intf->dev, ip, nm, nw, bc); if (testing) return 0; strcpy(req.ifr_name, intf->dev); addr.sin_family = AF_INET; addr.sin_port = 0; memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip)); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { errorWindow("socket: %s"); return 1; } memcpy(&req.ifr_addr, &addr, sizeof(addr)); if (ioctl(s, SIOCSIFADDR, &req)) { close(s); errorWindow("SIOCSIFADDR: %s"); return 1; } memcpy(&addr.sin_addr, &intf->broadcast, sizeof(intf->broadcast)); memcpy(&req.ifr_broadaddr, &addr, sizeof(addr)); if (ioctl(s, SIOCSIFBRDADDR, &req)) { close(s); errorWindow("SIOCSIFNETMASK: %s"); return 1; } memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask)); memcpy(&req.ifr_netmask, &addr, sizeof(addr)); if (ioctl(s, SIOCSIFNETMASK, &req)) { close(s); errorWindow("SIOCSIFNETMASK: %s"); return 1; } if (intf->isPtp) req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP; else req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST; if (ioctl(s, SIOCSIFFLAGS, &req)) { close(s); errorWindow("SIOCSIFFLAGS: %s"); return 1; } memset(&route, 0, sizeof(route)); route.rt_dev = intf->dev; route.rt_flags = RTF_UP; memcpy(&addr.sin_addr, &intf->network, sizeof(intf->netmask)); memcpy(&route.rt_dst, &addr, sizeof(addr)); memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask)); memcpy(&route.rt_genmask, &addr, sizeof(addr)); if (ioctl(s, SIOCADDRT, &route)) { close(s); errorWindow("SIOCADDRT: %s"); return 1; } intf->isUp = 1; return 0; } int netDeviceAvailable(char * device) { struct ifreq req; int s; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { close(s); errorWindow("socket: %s"); return 1; } strcpy(req.ifr_name, device); if (ioctl(s, SIOCGIFFLAGS, &req)) { /* if we can't get the flags, the networking device isn't available */ close(s); return 0; } return 1; } static void interfaceConfigToggle(newtComponent co, void * arg) { struct intfconfig_s * info = arg; int sense = NEWT_FLAGS_SET; if (*info->bootpState == ' ') sense = NEWT_FLAGS_RESET; newtEntrySetFlags(info->ipEntry, NEWT_ENTRY_DISABLED, sense); newtEntrySetFlags(info->nmEntry, NEWT_ENTRY_DISABLED, sense); newtEntrySetFlags(info->gwEntry, NEWT_ENTRY_DISABLED, sense); newtEntrySetFlags(info->nsEntry, NEWT_ENTRY_DISABLED, sense); newtRefresh(); } static char * findAvailableNetDevice(void) { char * devices[] = { "eth0", "tr0", "plip0", "plip1", "plip2", "fddi0", NULL }; char * device = NULL; char ** deviceptr; /* I should probably ask which device to use if multiple ones are available -- oh well :-( */ for (deviceptr = devices; *deviceptr; deviceptr++) { if (netDeviceAvailable(*deviceptr)) { device = *deviceptr; logMessage("%s is available -- using it for networking", device); break; } } return device; } static int setupNetworkInterface(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl, int justConfig) { newtComponent okay, cancel, bootp, f, answer; int top = 4; struct intfconfig_s c; struct in_addr addr; int32 ptpNetmask; int rc; int done = 0; char useBootp; char * device; struct driversLoaded * adriver; device = findAvailableNetDevice(); if (!device) { if ((rc = loadDeviceDriver(DRIVER_NET, dl, 0))) return rc; for (adriver = *dl; adriver && adriver->type != DRIVER_NET; adriver = adriver->next); if (!adriver) { logMessage("ack! loadDriveDriver() worked but didn't load a " "DRIVE_NET!!"); return INST_ERROR; } switch (adriver->minor) { case DRIVER_MINOR_ETHERNET: device = "eth0"; break; case DRIVER_MINOR_TR: device = "tr0"; break; case DRIVER_MINOR_PLIP: device = getPlipDeviceName(); break; default: exit(1); /* ack! */ } } newtCenteredWindow(50, 15, "Configure TCP/IP"); c.ipLabel = newtLabel(1, top + 2, "IP address:"); c.nmLabel = newtLabel(1, top + 3, "Netmask:"); c.gwLabel = newtLabel(1, top + 4, "Default gateway (IP):"); c.nsLabel = newtLabel(1, top + 5, "Primary nameserver:"); if (!intf->ip){ c.ipEntry = newtEntry(25, top + 2, "", 16, &c.ip, 0); } else { memcpy(&addr, &intf->ip, sizeof(intf->ip)); c.ipEntry = newtEntry(25, top + 2, inet_ntoa(addr), 16, &c.ip, 0); } if (!intf->netmask){ c.nmEntry = newtEntry(25, top + 3, "", 16, &c.nm, 0); } else { memcpy(&addr, &intf->netmask, sizeof(intf->netmask)); c.nmEntry = newtEntry(25, top + 3, inet_ntoa(addr), 16, &c.nm, 0); } if (!netc->defaultGateway) c.gwEntry = newtEntry(25, top + 4, "", 16, &c.gw, 0); else c.gwEntry = newtEntry(25, top + 4, netc->defaultGateway, 16, &c.gw, 0); if (!netc->nameserver[0]) c.nsEntry = newtEntry(25, top + 5, "", 16, &c.ns, 0); else c.nsEntry = newtEntry(25, top + 5, netc->nameserver[0], 16, &c.ns, 0); c.bootpState = &useBootp; f = newtForm(NULL, NULL, 0); bootp = newtCheckbox(1, top, "Configure device with bootp", (intf->isConfigured && intf->useBootp) ? '*' : ' ', NULL, &useBootp); newtComponentAddCallback(bootp, interfaceConfigToggle, &c); newtFormAddComponents(f, bootp, c.ipLabel, c.nmLabel, c.gwLabel, c.nsLabel, c.ipEntry, c.nmEntry, c.gwEntry, c.nsEntry, NULL); if (c.bootpState) newtFormSetCurrent(f, c.ipEntry); newtComponentAddCallback(c.ipEntry, ipCallback, &c); newtComponentAddCallback(c.nmEntry, ipCallback, &c); okay = newtButton(8, top + 7, "Ok"); cancel = newtButton(28, top + 7, "Cancel"); newtFormAddComponents(f, okay, cancel, NULL); do { answer = newtRunForm(f); if (answer == cancel) { newtFormDestroy(f); newtPopWindow(); return INST_CANCEL; } if (useBootp != ' ') { logMessage("Configuring device %s via bootp", device); if (justConfig) { done = 1; intf->useBootp = 1; intf->isConfigured = 1; } else if (!doBootp(device, intf, netc)) { done = 1; } } else { strcpy(intf->dev, device); inet_aton(c.ip, (struct in_addr *) &intf->ip); inet_aton(c.nm, (struct in_addr *) &intf->netmask); intf->broadcast = (intf->ip & intf->netmask) | (~intf->netmask); inet_aton("255.255.255.255", (struct in_addr *) &ptpNetmask); if (ptpNetmask == intf->netmask) { logMessage("configuring point to point device"); inet_aton(c.gw, (struct in_addr *) &intf->network); intf->isPtp = 1; } else { intf->network = intf->ip & intf->netmask; intf->isPtp = 0; } intf->isConfigured = 1; intf->useBootp = 0; strcpy(netc->defaultGateway, c.gw); if (netc->nameserver[0]) free(netc->nameserver[0]); if (strlen(c.ns)) netc->nameserver[0] = strdup(c.ns); else netc->nameserver[0] = NULL; netc->isConfigured = 1; done = 1; } } while (!done); newtFormDestroy(f); newtPopWindow(); if (!justConfig) { if (configureNetDevice(intf)) return INST_ERROR; if (addDefaultRoute(*netc)) return INST_ERROR; } return 0; } static void hnCallback(newtComponent co, void * dptr) { char * buf; struct netconfig_s * data = dptr; if (strlen(data->hn)) return; if (!strlen(data->dn)) return; buf = alloca(strlen(data->dn) + 5); strcpy(buf, "."); strcat(buf, data->dn); newtEntrySet(data->hnEntry, buf, 0); } static void ipCallback(newtComponent co, void * dptr) { struct intfconfig_s * data = dptr; struct in_addr ipaddr, nmaddr, addr; char * ascii; int32 broadcast, network; if (co == data->ipEntry) { if (strlen(data->ip) && !strlen(data->nm)) { if (inet_aton(data->ip, &ipaddr)) { ipaddr.s_addr = ntohl(ipaddr.s_addr); if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 127) ascii = "255.0.0.0"; else if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 191) ascii = "255.255.0.0"; else ascii = "255.255.255.0"; newtEntrySet(data->nmEntry, ascii, 1); } } } else if (co == data->nmEntry) { if (!strlen(data->ip) || !strlen(data->nm)) return; if (!inet_aton(data->ip, &ipaddr)) return; if (!inet_aton(data->nm, &nmaddr)) return; network = ipaddr.s_addr & nmaddr.s_addr; broadcast = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr); addr.s_addr = htonl(ntohl(broadcast) - 1); newtEntrySet(data->gwEntry, inet_ntoa(addr), 1); /* I'm such a lazy bastard */ if ((ntohl(network) & 0xFFFFFF00) == 0xc7b71800) { newtEntrySet(data->nsEntry, "199.183.24.1", 1); } else { addr.s_addr = htonl(ntohl(network) + 1); newtEntrySet(data->nsEntry, inet_ntoa(addr), 1); } } } int writeNetConfig(char * prefix, struct netConfig * netc, struct netInterface * gwdev, int verbose) { char filename[100]; FILE * f; if (testing) return 0; sprintf(filename, "%s/network", prefix); f = fopen(filename, "w"); if (!f) { errorWindow("cannot create network config file: %s"); return INST_ERROR; } fprintf(f, "NETWORKING=yes\n"); fprintf(f, "FORWARD_IPV4=false\n"); logMessage("writing network information to %s", filename); if (netc->hostname && strlen(netc->hostname)) { logMessage("\tnetwork is configured, writing complete information"); fprintf(f, "HOSTNAME=%s\n", netc->hostname); fprintf(f, "DOMAINNAME=%s\n", netc->domainname); if (gwdev && strlen(netc->defaultGateway)) { fprintf(f, "GATEWAY=%s\n", netc->defaultGateway); fprintf(f, "GATEWAYDEV=%s\n", gwdev->dev); } if (verbose) { if (netc->nameserver[0]) fprintf(f, "NS1=%s\n", netc->nameserver[0]); if (netc->nameserver[1]) fprintf(f, "NS2=%s\n", netc->nameserver[1]); if (netc->nameserver[2]) fprintf(f, "NS3=%s\n", netc->nameserver[2]); } } else { logMessage("\tnetwork is not configured"); fprintf(f, "HOSTNAME=localhost.localdomain\n"); } fclose(f); return 0; } int writeHosts(char * prefix, struct netConfig * netc, struct netInterface * intf) { char filename[100]; FILE * f; struct in_addr * addrptr; char * nickname; int i; if (testing) return 1; sprintf(filename, "%s/hosts", prefix); /* if /etc/hosts already exists, don't bother creating one */ if (!access(filename, R_OK)) { logMessage("%s already exists -- won't crunch it", filename); return 0; } logMessage("%s doesn not exist -- creating", filename); f = fopen(filename, "w"); if (!f) { errorWindow("cannot create /etc/hosts: %s"); return INST_ERROR; } logMessage("writing host information to %s", filename); fprintf(f, "127.0.0.1\t\tlocalhost localhost.localdomain\n"); if (netc->hostname && strlen(netc->hostname)) { addrptr = (struct in_addr *) &intf->ip; i = strlen(netc->hostname) - strlen(netc->domainname); if (i > 1 && !strcmp(netc->hostname + i, netc->domainname) && netc->hostname[i - 1] == '.') { nickname = strdup(netc->hostname); nickname[i - 1] = '\0'; fprintf(f, "%s\t\t%s %s\n", inet_ntoa(*addrptr), netc->hostname, nickname); free(nickname); } else { fprintf(f, "%s\t\t%s\n", inet_ntoa(*addrptr), netc->hostname); } sethostname(netc->hostname, strlen(netc->hostname)); } fclose(f); res_init(); /* reinit the resolver so DNS changes take affect */ return 0; } int writeResolvConf(char * prefix, struct netConfig * netc) { char filename[100]; FILE * f; if (testing) return 1; if (!netc->domainname && !netc->nameserver[0]) { logMessage("networking is not configured - not writing resolv.conf"); return 0; } sprintf(filename, "%s/resolv.conf", prefix); f = fopen(filename, "w"); if (!f) { errorWindow("cannot create resolv.conf: %s"); return INST_ERROR; } logMessage("writing nameservices information to %s", filename); if (netc->domainname) fprintf(f, "search %s\n", netc->domainname); if (netc->nameserver[0]) fprintf(f, "nameserver %s\n", netc->nameserver[0]); if (netc->nameserver[1]) fprintf(f, "nameserver %s\n", netc->nameserver[1]); if (netc->nameserver[2]) fprintf(f, "nameserver %s\n", netc->nameserver[2]); fclose(f); res_init(); /* reinit the resolver so DNS changes take affect */ return 0; } int writeNetInterfaceConfig(char * prefix, struct netInterface * intf) { char filename[100]; FILE * f; struct in_addr * addrptr; if (testing) return 0; if (!intf->isConfigured) { logMessage("network interface is not configured - not creating " "ifcfg-*"); return(0); } sprintf(filename, "%s/ifcfg-%s", prefix, intf->dev); f = fopen(filename, "w"); if (!f) { errorWindow("cannot create network device config file: %s"); return INST_ERROR; } logMessage("writing network information to %s", filename); fprintf(f, "DEVICE=%s\n", intf->dev); if (intf->useBootp) fprintf(f, "BOOTPROTO=bootp\n"); if (!strcmp(prefix, "/tmp") || !intf->useBootp) { addrptr = (struct in_addr *) &intf->ip; fprintf(f, "IPADDR=%s\n", inet_ntoa(*addrptr)); addrptr = (struct in_addr *) &intf->netmask; fprintf(f, "NETMASK=%s\n", inet_ntoa(*addrptr)); addrptr = (struct in_addr *) &intf->network; fprintf(f, "NETWORK=%s\n", inet_ntoa(*addrptr)); addrptr = (struct in_addr *) &intf->broadcast; fprintf(f, "BROADCAST=%s\n", inet_ntoa(*addrptr)); } fprintf(f, "ONBOOT=yes\n"); fclose(f); return 0; } int readNetInterfaceConfig(char * prefix, char * device, struct netInterface * intf) { FILE * f; char * start, * end; char buf[250]; int line = 0; intf->isConfigured = 0; if (testing) { return 0; } sprintf(buf, "%s/ifcfg-%s", prefix, device); f = fopen(buf, "r"); if (!f) { if (errno != ENOENT) { errorWindow("cannot open file: %s"); return INST_ERROR; } else { intf->ip = 0; return 0; } } while (fgets(buf, sizeof(buf) - 1, f)) { line++; start = buf; /* skipping leading spaces */ while (*start && isspace(*start)) start++; if (!*start) continue; /* skip comments */ if (*start == '#') continue; /* cut off trailing spaces and \n */ end = start + strlen(start) - 2; while (isspace(*end)) end--; end++; *end = '\0'; end--; if (!strncmp("IPADDR=", start, 7)) { start += 7; inet_aton(start, (struct in_addr *) &intf->ip); } else if (!strncmp("DEVICE=", start, 7)) { start += 7; strcpy(intf->dev, start); } else if (!strncmp("BOOTPROTO=bootp", start, 15)) { intf->useBootp = 1; } else if (!strncmp("NETMASK=", start, 8)) { start += 8; inet_aton(start, (struct in_addr *) &intf->netmask); } else if (!strncmp("NETWORK=", start, 8)) { start += 8; inet_aton(start, (struct in_addr *) &intf->network); if (!strcmp(start, "255.255.255.255")) intf->isPtp = 1; } else if (!strncmp("BROADCAST=", start, 10)) { start += 10; inet_aton(start, (struct in_addr *) &intf->broadcast); } } fclose(f); intf->isConfigured = 1; return 0; } int configureNetwork(struct netConfig * netc, struct netInterface * intf) { struct netconfig_s n; int top = 3; newtComponent f, okay, cancel, answer; int i; n.dnLabel = newtLabel(1, top , "Domain name:"); n.hnLabel = newtLabel(1, top + 1, "Host name:"); n.nsLabels[1] = newtLabel(1, top + 2, "Secondary nameserver (IP):"); n.nsLabels[2] = newtLabel(1, top + 3, "Tertiary nameserver (IP):"); n.dnEntry = newtEntry(28, top , "", 20, &n.dn, NEWT_ENTRY_SCROLL); n.hnEntry = newtEntry(28, top + 1, "", 20, &n.hn, NEWT_ENTRY_SCROLL); n.nsEntrys[1] = newtEntry(28, top + 2, "", 20, &n.ns[1], NEWT_ENTRY_SCROLL); n.nsEntrys[2] = newtEntry(28, top + 3, "", 20, &n.ns[2], NEWT_ENTRY_SCROLL); if (!strlen(netc->hostname) && !strlen(netc->domainname) && (testing || intf->isUp) && netc->nameserver[0]) { guessHostname(intf, netc); if (netc->hostname[0] && netc->domainname[0] && !expert) { logMessage("reverse name lookup worked; skipping hostname config"); return 0; } } newtCenteredWindow(50, 15, "Configure Network"); if (netc->hostname) newtEntrySet(n.hnEntry, netc->hostname, 0); if (netc->domainname) newtEntrySet(n.dnEntry, netc->domainname, 0); if (netc->nameserver[1]) newtEntrySet(n.nsEntrys[1], netc->nameserver[1], 0); if (netc->nameserver[2]) newtEntrySet(n.nsEntrys[2], netc->nameserver[2], 0); newtComponentAddCallback(n.dnEntry, hnCallback, &n); f = newtForm(NULL, NULL, 0); newtFormAddComponents(f, n.dnLabel, n.hnLabel, n.nsLabels[1], n.nsLabels[2], NULL); newtFormAddComponents(f, n.dnEntry, n.hnEntry, n.nsEntrys[1], n.nsEntrys[2], NULL); okay = newtButton(11, 11, "Ok"); cancel = newtButton(30, 11, "Cancel"); newtFormAddComponents(f, okay, cancel, NULL); answer = newtRunForm(f); strcpy(netc->hostname, n.hn); strcpy(netc->domainname, n.dn); for (i = 1; i < 3; i++) { if (netc->nameserver[i]) free(netc->nameserver[i]); netc->nameserver[i] = *n.ns[i] ? strdup(n.ns[i]) : NULL; } newtFormDestroy(f); newtPopWindow(); if (answer == cancel) return INST_CANCEL; netc->isConfigured = 1; return 0; } int readNetConfig(char * prefix, struct netConfig * netc) { FILE * f; char * start, * end; char buf[250]; int line = 0; if (testing) { return 0; } sprintf(buf, "%s/network", prefix); f = fopen(buf, "r"); if (!f) { if (errno != ENOENT) { errorWindow("cannot open file: %s"); return INST_ERROR; } else { netc->hostname[0] = '\0'; return 0; } } memset(netc, 0, sizeof(*netc)); while (fgets(buf, sizeof(buf) - 1, f)) { line++; start = buf; /* skipping leading spaces */ while (*start && isspace(*start)) start++; if (!*start) continue; /* skip comments */ if (*start == '#') continue; /* cut off trailing spaces and \n */ end = start + strlen(start) - 2; while (isspace(*end)) end--; end++; *end = '\0'; end--; if (!strncmp("HOSTNAME=", start, 9)) { start += 9; strcpy(netc->hostname, start); } else if (!strncmp("DOMAINNAME=", start, 11)) { start += 11; strcpy(netc->domainname, start); } else if (!strncmp("GATEWAY=", start, 8)) { start += 8; strcpy(netc->defaultGateway, start); } else if (!strncmp("NS1=", start, 4)) { start += 4; netc->nameserver[0] = strdup(start); } else if (!strncmp("NS2=", start, 4)) { start += 4; netc->nameserver[1] = strdup(start); } else if (!strncmp("NS3=", start, 4)) { start += 4; netc->nameserver[2] = strdup(start); } } fclose(f); netc->isConfigured = 1; return 0; } int bringUpNetworking(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl) { return doBringUpNetworking(intf, netc, dl, 0); } #define BRINGUP_NET 1 #define BRINGUP_CONF 2 #define BRINGUP_ROUTE 3 #define BRINGUP_DONE 4 static int doBringUpNetworking(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl, int justConfig) { int where = BRINGUP_NET; int rc; char * device; if (kickstart) { if (intf->isConfigured && netc->isConfigured) return 0; /* justConfig must be zero, we have to actually do something for this to happen automatically */ device = findAvailableNetDevice(); if (!device) { if ((rc = loadDeviceDriver(DRIVER_NET, dl, 1))) { newtWinMessage("Ethernet Probe", "Ok", "The Ethernet probe failed " "to find a card on your system. Press to manually " "configure one."); while (setupNetworkInterface(intf, netc, dl, 0)) ; } if (!(device = findAvailableNetDevice())) { newtWinMessage("Network Failed", "Hang", "No networking " "devices are available. You should never " "have gotten this far."); } } while (doBootp(device, intf, netc)) { newtWinMessage("Bootp Failed", "Retry", "Bootp failed to find an " "IP address. Press to retry."); } configureNetDevice(intf); addDefaultRoute(*netc); while (guessHostname(intf, netc)) { newtWinMessage("Hostname Lookup", "Retry", "I cannot find by hostname via DNS. Press to retry."); } return addDefaultRoute(*netc); } while (where != BRINGUP_DONE) { switch (where) { case BRINGUP_NET: rc = setupNetworkInterface(intf, netc, dl, justConfig); if (rc) return rc; where = BRINGUP_CONF; break; case BRINGUP_CONF: rc = configureNetwork(netc, intf); if (rc == INST_CANCEL) where = BRINGUP_NET; else if (rc) return INST_ERROR; else where = BRINGUP_ROUTE; break; case BRINGUP_ROUTE: if (justConfig) rc = 0; else rc = addDefaultRoute(*netc); if (rc) return rc; where = BRINGUP_DONE; break; } } /* write out the /etc/resolv.conf, as we'll need that to use name services properly */ writeResolvConf("/etc", netc); return 0; } #define CHECKNET_CONFIG 1 #define CHECKNET_KEEP 2 #define CHECKNET_NONE 3 #define CHECKNET_NOBOOTP 4 static int checkNetConfigPanel(int isConfigured, int useBootp, int * choice) { newtComponent text, okay, cancel; newtComponent f, answer, yes, no, listbox; int which; if (isConfigured && kickstart) { *choice = CHECKNET_KEEP; return 0; } else if (isConfigured) { newtCenteredWindow(42, 13, "Network Configuration"); text = newtTextbox(1, 1, 40, 2, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, "LAN networking has already been configured. Do you " "want to:"); listbox = newtListbox(8, 4, 0, NEWT_LISTBOX_RETURNEXIT); if (useBootp) { newtListboxAddEntry(listbox, "Use bootp at startup", (void *) 1); newtListboxAddEntry(listbox, "Use the current IP information", (void *) 4); newtListboxAddEntry(listbox, "Reconfigure network now", (void *) 2); newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3); } else { newtListboxAddEntry(listbox, "Keep this setup", (void *) 1); newtListboxAddEntry(listbox, "Reconfigure network now", (void *) 2); newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3); } okay = newtButton(6, 9, "Ok"); cancel = newtButton(23, 9, "Cancel"); f = newtForm(NULL, NULL, 0); newtFormAddComponents(f, text, listbox, okay, cancel, NULL); answer = newtRunForm(f); if (answer == cancel) { newtPopWindow(); newtFormDestroy(f); return INST_CANCEL; } which = (int) newtListboxGetCurrent(listbox); newtPopWindow(); newtFormDestroy(f); if (which == 1) *choice = CHECKNET_KEEP; else if (which == 3) *choice = CHECKNET_NONE; else if (which == 4) *choice = CHECKNET_NOBOOTP; else *choice = CHECKNET_CONFIG; } else if (kickstart) { /* XXX this ought to be configurable */ *choice = CHECKNET_NONE; } else { newtCenteredWindow(42, 10, "Network Configuration"); text = newtTextbox(1, 1, 40, 3, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, "Do you want to configure LAN (not dialup) networking " "for your installed system?"); yes = newtButton(3, 6, " Yes "); no = newtButton(16, 6, " No "); cancel = newtButton(29, 6, "Cancel"); f = newtForm(NULL, NULL, 0); newtFormAddComponents(f, text, yes, no, cancel, NULL); answer = newtRunForm(f); if (answer == f) answer = newtFormGetCurrent(f); newtPopWindow(); newtFormDestroy(f); if (answer == yes) { *choice = CHECKNET_CONFIG; } else if (answer == cancel) { return INST_CANCEL; } else { *choice = CHECKNET_NONE; } } return 0; } int checkNetConfig(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl) { int choice, rc; /* this doesn't handle cancel very well as the dl makes it difficult :-( */ do { rc = checkNetConfigPanel(netc->isConfigured && intf->isConfigured, intf->useBootp, &choice); if (rc) return rc; switch (choice) { case CHECKNET_NOBOOTP: intf->useBootp = 0; rc = 0; break; case CHECKNET_CONFIG: rc = doBringUpNetworking(intf, netc, dl, 1); if (rc == INST_ERROR) return rc; break; case CHECKNET_NONE: intf->isConfigured = netc->isConfigured = 0; rc = 0; break; } } while (rc); return 0; }