#include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, brLabel, naLabel; newtComponent ipEntry, nmEntry, brEntry, naEntry; char * ip, * nm, * br, * na; }; struct netconfig_s { newtComponent nsLabels[3], gwLabel, hnLabel, dnLabel; newtComponent nsEntrys[3], gwEntry, hnEntry, dnEntry; char * ns[3], * gw, * hn, * dn; }; static void ipCallback(newtComponent co, void * data); static void hnCallback(newtComponent co, void * data); static int setupNetworkInterface(char * device, struct netInterface * intf, struct driversLoaded ** dl, int justConfig); static int doBringUpNetworking(struct netInterface * intf, struct netConfig * netc, struct driversLoaded ** dl, int justConfig); 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; } 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; } req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; 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; } 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 int setupNetworkInterface(char * device, struct netInterface * intf, struct driversLoaded ** dl, int justConfig) { newtComponent okay, cancel, f, answer; int top = 3; struct intfconfig_s c; struct in_addr addr; int rc; if (!netDeviceAvailable(device)) { if ((rc = loadDeviceDriver(DRIVER_ETHERNET, dl))) return rc; } newtOpenWindow(17, 4, 45, 15, "Configure TCP/IP"); c.ipLabel = newtLabel(1, top , "IP address:"); c.nmLabel = newtLabel(1, top + 1, "Netmask:"); c.naLabel = newtLabel(1, top + 2, "Network address:"); c.brLabel = newtLabel(1, top + 3, "Broadcast address:"); if (!intf->isConfigured){ c.ipEntry = newtEntry(20, top , "", 16, &c.ip, 0); c.nmEntry = newtEntry(20, top + 1, "", 16, &c.nm, 0); c.naEntry = newtEntry(20, top + 2, "", 16, &c.na, 0); c.brEntry = newtEntry(20, top + 3, "", 16, &c.br, 0); } else { memcpy(&addr, &intf->ip, sizeof(intf->ip)); c.ipEntry = newtEntry(20, top , inet_ntoa(addr), 16, &c.ip, 0); memcpy(&addr, &intf->netmask, sizeof(intf->netmask)); c.nmEntry = newtEntry(20, top + 1, inet_ntoa(addr), 16, &c.nm, 0); memcpy(&addr, &intf->network, sizeof(intf->network)); c.naEntry = newtEntry(20, top + 2, inet_ntoa(addr), 16, &c.na, 0); memcpy(&addr, &intf->broadcast, sizeof(intf->broadcast)); c.brEntry = newtEntry(20, top + 3, inet_ntoa(addr), 16, &c.br, 0); } f = newtForm(NULL, NULL, 0); newtFormAddComponents(f, c.ipLabel, c.nmLabel, c.naLabel, c.brLabel, c.ipEntry, c.nmEntry, c.naEntry, c.brEntry, NULL); newtComponentAddCallback(c.ipEntry, ipCallback, &c); newtComponentAddCallback(c.nmEntry, ipCallback, &c); okay = newtButton(8, 10, "Ok"); cancel = newtButton(28, 10, "Cancel"); newtFormAddComponents(f, okay, cancel, NULL); answer = newtRunForm(f); if (answer == cancel) { newtFormDestroy(f); newtPopWindow(); return INST_CANCEL; } strcpy(intf->dev, device); inet_aton(c.ip, (struct in_addr *) &intf->ip); inet_aton(c.nm, (struct in_addr *) &intf->netmask); inet_aton(c.br, (struct in_addr *) &intf->broadcast); inet_aton(c.na, (struct in_addr *) &intf->network); intf->isConfigured = 1; if (!justConfig) if (configureNetDevice(*intf)) return INST_ERROR; newtFormDestroy(f); newtPopWindow(); 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; 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; if (!strlen(data->na)) { addr.s_addr = ipaddr.s_addr & nmaddr.s_addr; ascii = inet_ntoa(addr); newtEntrySet(data->naEntry, ascii, 1); } if (!strlen(data->br)) { addr.s_addr = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr); ascii = inet_ntoa(addr); newtEntrySet(data->brEntry, ascii, 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"); logMessage("writing network information to %s", filename); if (netc->isConfigured) { 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\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); 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\n"); if (netc->isConfigured) { 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); return 0; } int writeResolvConf(char * prefix, struct netConfig * netc) { char filename[100]; FILE * f; if (testing) return 1; if (!netc->isConfigured) { 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); 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); 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); 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("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); } else if (!strncmp("BROADCAST=", start, 10)) { start += 10; inet_aton(start, (struct in_addr *) &intf->broadcast); } } fclose(f); strcpy(intf->dev, device); intf->useBootp = 0; intf->isConfigured = 1; return 0; } int configureNetwork(struct netConfig * netc, const struct netInterface * intf) { struct netconfig_s n; int top = 3; newtComponent f, okay, cancel, answer; struct in_addr ia; int32 ipnum; char * chptr; int i; newtOpenWindow(15, 4, 50, 15, "Configure Network"); n.dnLabel = newtLabel(1, top , "Domain name:"); n.hnLabel = newtLabel(1, top + 1, "Host name:"); n.gwLabel = newtLabel(1, top + 2, "Default gateway (IP):"); n.nsLabels[0] = newtLabel(1, top + 3, "Primary nameserver (IP):"); n.nsLabels[1] = newtLabel(1, top + 4, "Secondary nameserver (IP):"); n.nsLabels[2] = newtLabel(1, top + 5, "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.gwEntry = newtEntry(28, top + 2, "", 20, &n.gw, NEWT_ENTRY_SCROLL); n.nsEntrys[0] = newtEntry(28, top + 3, "", 20, &n.ns[0], NEWT_ENTRY_SCROLL); n.nsEntrys[1] = newtEntry(28, top + 4, "", 20, &n.ns[1], NEWT_ENTRY_SCROLL); n.nsEntrys[2] = newtEntry(28, top + 5, "", 20, &n.ns[2], NEWT_ENTRY_SCROLL); if (netc->isConfigured) { newtEntrySet(n.hnEntry, netc->hostname, 0); newtEntrySet(n.dnEntry, netc->domainname, 0); newtEntrySet(n.gwEntry, netc->defaultGateway, 0); if (netc->nameserver[0]) newtEntrySet(n.nsEntrys[0], netc->nameserver[0], 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); } else if (intf->isConfigured) { ipnum = htonl(ntohl(intf->broadcast) - 1); memcpy(&ia, &ipnum, sizeof(ipnum)); newtEntrySet(n.gwEntry, inet_ntoa(ia), 1); ipnum = htonl(ntohl(intf->network) + 1); memcpy(&ia, &ipnum, sizeof(ipnum)); newtEntrySet(n.nsEntrys[0], inet_ntoa(ia), 1); } newtComponentAddCallback(n.dnEntry, hnCallback, &n); f = newtForm(NULL, NULL, 0); newtFormAddComponents(f, n.dnLabel, n.hnLabel, n.gwLabel, n.nsLabels[0], n.nsLabels[1], n.nsLabels[2], NULL); newtFormAddComponents(f, n.dnEntry, n.hnEntry, n.gwEntry, n.nsEntrys[0], 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); chptr = n.gw; while (isspace(*chptr) && *chptr) chptr++; if (!isspace(*chptr) || *chptr) strcpy(netc->defaultGateway, n.gw); else strcpy(netc->defaultGateway, ""); for (i = 0; i < 3; i++) { if (netc->isConfigured && 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; netc->isConfigured = 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; while (where != BRINGUP_DONE) { switch (where) { case BRINGUP_NET: rc = setupNetworkInterface("eth0", intf, 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 static int checkNetConfigPanel(int isConfigured, int * choice) { newtComponent text, okay, cancel; newtComponent f, answer, yes, no, listbox; int which; if (isConfigured) { newtOpenWindow(18, 5, 42, 12, "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); newtListboxAddEntry(listbox, "Keep this setup", (void *) 1); newtListboxAddEntry(listbox, "Reconfigure network", (void *) 2); newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3); okay = newtButton(6, 8, "Ok"); cancel = newtButton(23, 8, "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 *choice = CHECKNET_CONFIG; } else { newtOpenWindow(18, 6, 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, &choice); if (rc) return rc; switch (choice) { 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; }