#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootpc.h" #include "devices.h" #include "dns.h" #include "install.h" #include "intl.h" #include "kickstart.h" #include "log.h" #include "newt.h" #include "net.h" #include "popt.h" #include "windows.h" typedef unsigned int int32; struct intfconfig_s { newtComponent ipEntry, nmEntry, gwEntry, nsEntry; char * ip, * nm, * gw, * ns; }; struct netconfig_s { 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); static int doBringUpNetworking(struct intfInfo * currIntf, struct netInfo * currNetc, struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, int dir, int justConfig); static int configureNetDevice(struct intfInfo * intf); /* intf in configureNetwork is optional */ static int configureNetwork(struct netInfo * currNetc, struct intfInfo * currIntf, struct netInfo * netc, struct intfInfo * intf, int justConfig, int dir); static char * findAvailableNetDevice(void); static int getAvailableNetDevice(struct driversLoaded ** dl, char ** devicePtr); static int guessHostname(struct intfInfo * realIntf, struct netInfo * realNet, struct intfInfo * targetIntf, struct netInfo * targetNet); static int addDefaultRoute(struct netInfo * net); static int setupNetworkInterface(struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, int justConfig, int dir); static int getStaticIPInfo(struct intfInfo * intf, struct netInfo * net); static int checkNetConfigPanel(struct intfInfo * intf, int * choice); /* The interface/gateway needs to be configured before this will work! */ static int guessHostname(struct intfInfo * realIntf, struct netInfo * realNet, struct intfInfo * targetIntf, struct netInfo * targetNet) { char ips[50]; char * name, * chptr; if (!testing) if (!realIntf->isUp || !(realNet->set & NETINFO_HAS_DNS)) return 1; if ((realNet->set & NETINFO_HAS_HOSTNAME) && (realNet->set & NETINFO_HAS_DOMAIN)) return 0; writeResolvConf("/etc", realNet); strcpy(ips, inet_ntoa(targetIntf->ip)); winStatus(40, 3, _("Hostname"), _("Determining host name and domain...")); name = mygethostbyaddr(ips); if (name) name = mygethostbyaddr(ips); newtPopWindow(); if (!name) { logMessage("reverse name lookup failed"); return 1; } logMessage("reverse name lookup worked"); if (!(realNet->manuallySet & NETINFO_HAS_HOSTNAME)) { if (realNet->hostname) free(realNet->hostname); realNet->hostname = strdup(name); realNet->set |= NETINFO_HAS_HOSTNAME; } if (!(realNet->manuallySet & NETINFO_HAS_DOMAIN)) { for (chptr = name; *chptr && (*chptr != '.'); chptr++) ; if (*chptr == '.') { if (realNet->domain) free(realNet->domain); realNet->domain = strdup(chptr + 1); realNet->set |= NETINFO_HAS_DOMAIN; } } return 0; } static int addDefaultRoute(struct netInfo * net) { int s; struct rtentry route; struct sockaddr_in addr; if (testing) return 0; /* It should be okay to try and setup a machine w/o a default gateway */ if (!(net->set & NETINFO_HAS_GATEWAY)) 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; addr.sin_addr = net->gateway; 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 intfInfo * 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->device, ip, nm, nw, bc); if (testing) return 0; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { errorWindow("socket: %s"); return 1; } strcpy(req.ifr_name, intf->device); req.ifr_flags &= ~(IFF_UP | IFF_RUNNING); /* Take down iface */ if (ioctl(s, SIOCSIFFLAGS, &req)) { close(s); errorWindow("SIOCSIFFLAGS: %s"); return 1; } addr.sin_port = 0; memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip)); 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->device; 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 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; } /* Make a networking device available. If one is already configured use it, otherwise probe for one, and if that fails, ask. */ static int getAvailableNetDevice(struct driversLoaded ** dl, char ** devicePtr) { char * device; struct driversLoaded * adriver; int rc; device = findAvailableNetDevice(); if (!device) { /* in kickstart mode, just probe for a device */ rc = loadDeviceDriver(DRIVER_NET, dl, kickstart ? DEVICE_JUSTPROBE : 0); if (rc && kickstart) { /* we can't go any further without a network device! */ newtWinMessage(_("Ethernet Probe"), _("Ok"), _("The Ethernet probe failed " "to find a card on your system. Press to manually " "configure one.")); rc = loadDeviceDriver(DRIVER_NET, dl, 0); } if (rc) { 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: /* keep gcc from complaining */ } } *devicePtr = device; return 0; } static int getStaticIPInfo(struct intfInfo * intf, struct netInfo * net) { newtComponent okay, back, f, answer, text; struct in_addr addr; struct intfconfig_s c; struct in_addr ptpNetmask; newtGrid grid, subgrid, buttons; int rc; text = newtTextboxReflowed(-1, -1, _("Please enter the IP configuration for this machine. Each " "item should be entered as an IP address in dotted-decimal " "notation (for example, 1.2.3.4)."), 50, 5, 10, 0); subgrid = newtCreateGrid(2, 4); newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("IP address:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Netmask:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Default gateway (IP):")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 3, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Primary nameserver:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); c.ipEntry = newtEntry(-1, -1, intf->set & INTFINFO_HAS_IP ? inet_ntoa(intf->ip) : NULL, 16, &c.ip, 0); c.nmEntry = newtEntry(-1, -1, intf->set & INTFINFO_HAS_NETMASK ? inet_ntoa(intf->netmask) : NULL, 16, &c.nm, 0); c.gwEntry = newtEntry(-1, -1, net->set & NETINFO_HAS_GATEWAY ? inet_ntoa(net->gateway) : NULL, 16, &c.gw, 0); c.nsEntry = newtEntry(-1, -1, net->set & NETINFO_HAS_DNS ? inet_ntoa(net->dnsServers[0]) : NULL, 16, &c.ns, 0); newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, c.ipEntry, 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, c.nmEntry, 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 2, NEWT_GRID_COMPONENT, c.gwEntry, 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 3, NEWT_GRID_COMPONENT, c.nsEntry, 1, 0, 0, 0, 0, 0); buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &back, NULL); grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid, 0, 1, 0, 1, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); f = newtForm(NULL, NULL, 0); newtGridAddComponentsToForm(grid, f, 1); newtGridWrappedWindow(grid, _("Configure TCP/IP")); newtGridFree(grid, 1); newtComponentAddCallback(c.ipEntry, ipCallback, &c); newtComponentAddCallback(c.nmEntry, ipCallback, &c); do { answer = newtRunForm(f); if (answer == back) { newtFormDestroy(f); newtPopWindow(); return INST_CANCEL; } if (*c.ip && inet_aton(c.ip, &addr)) { if (!(intf->set & INTFINFO_HAS_IP) || memcmp(&addr, &intf->ip, 4)) { intf->ip = addr; intf->set |= INTFINFO_HAS_IP; intf->manuallySet |= INTFINFO_HAS_IP; net->set = ~(NETINFO_HAS_HOSTNAME | NETINFO_HAS_DOMAIN); net->manuallySet = ~(NETINFO_HAS_HOSTNAME | NETINFO_HAS_DOMAIN); } } else { intf->set &= ~INTFINFO_HAS_IP; } if (*c.nm && inet_aton(c.nm, &addr)) { if (!(intf->set & INTFINFO_HAS_NETMASK) || memcmp(&addr, &intf->netmask, 4)) { intf->netmask = addr; intf->set |= INTFINFO_HAS_NETMASK; intf->manuallySet |= INTFINFO_HAS_NETMASK; } } else { intf->set &= ~INTFINFO_HAS_NETMASK; } rc = (intf->set & INTFINFO_HAS_IP) && (intf->set & INTFINFO_HAS_NETMASK); if (!rc) { newtWinMessage(_("Missing Information"), _("Retry"), _("You must enter both a valid IP address and a " "netmask.")); } } while (!rc); if (*c.gw && inet_aton(c.gw, &addr)) { if (!(net->set & NETINFO_HAS_GATEWAY) || memcmp(&addr, &net->gateway, 4)) { net->gateway = addr; net->set |= NETINFO_HAS_GATEWAY; net->manuallySet |= NETINFO_HAS_GATEWAY; } } else { net->set &= ~NETINFO_HAS_GATEWAY; } if (*c.ns && inet_aton(c.ns, &addr)) { if (!(net->set & NETINFO_HAS_DNS) || memcmp(&addr, &net->dnsServers[0], 4)) { net->dnsServers[0] = addr; net->set |= NETINFO_HAS_DNS; net->manuallySet |= NETINFO_HAS_DNS; if (!net->numDns) net->numDns = 1; } } else { net->set &= ~NETINFO_HAS_DNS; net->numDns = 0; } *((int32 *) &intf->broadcast) = (*((int32 *) &intf->ip) & *((int32 *) &intf->netmask)) | ~(*((int32 *) &intf->netmask)); inet_aton("255.255.255.255", &ptpNetmask); if (!memcmp(&ptpNetmask, &intf->netmask, 4)) { logMessage("configuring point to point device"); intf->network = net->gateway; intf->set |= INTFINFO_HAS_NETWORK; intf->isPtp = 1; } else { *((int32 *) &intf->network) = *((int32 *) &intf->ip) & *((int32 *) &intf->netmask); intf->set |= INTFINFO_HAS_NETWORK; intf->isPtp = 0; } if (intf->manuallySet) intf->bootProto = BOOTPROTO_STATIC; newtFormDestroy(f); newtPopWindow(); return 0; } /* This does four things: 1) finds a network device (via getAvailableNetDevice()) 2) asks what boot protocol to use for the net device 3) gets the IP information setup for the device (including gateway) 4) configures the device (including gateway) It works fine in kickstart mode. */ static char * bootProtocolList[] = { N_("Static IP address"), N_("BOOTP"), N_("DHCP"), NULL , }; static int setupNetworkInterface(struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, int justConfig, int dir) { int rc, i; char * device; int check; char * chptr; char ** ksArgv; int ksArgc; struct in_addr * parseAddress; int netSet, intfSet; poptContext optCon; char * arg; enum { SETUP_NETWORK_DETECT, SETUP_NETWORK_METHOD, SETUP_NETWORK_SETUP, SETUP_NETWORK_DONE } stage; struct poptOption ksOptions[] = { { "bootproto", '\0', POPT_ARG_STRING, NULL, 'b' }, { "gateway", '\0', POPT_ARG_STRING, NULL, 'g' }, { "ip", '\0', POPT_ARG_STRING, NULL, 'i' }, { "nameserver", '\0', POPT_ARG_STRING, NULL, 'n' }, { "netmask", '\0', POPT_ARG_STRING, NULL, 'm' }, { 0, 0, 0, 0, 0 } }; for (i = 0; bootProtocolList[i]; i++) bootProtocolList[i] = F_(bootProtocolList[i]); if ((dir > 0) || (!(intf->set & INTFINFO_HAS_DEVICE))) { stage = SETUP_NETWORK_DETECT; } else { if ((intf->set & INTFINFO_HAS_BOOTPROTO) && (intf->bootProto == BOOTPROTO_STATIC)) stage = SETUP_NETWORK_SETUP; else stage = SETUP_NETWORK_METHOD; } if (kickstart) { if (ksGetCommand(KS_CMD_NETWORK, NULL, &ksArgc, &ksArgv)) { /* This is for compatibility with RH 5.0 */ ksArgv = alloca(sizeof(*ksArgv) * 1); ksArgv[0] = "network"; ksArgc = 1; } logMessage("got %d args", ksArgc); optCon = poptGetContext(NULL, ksArgc, ksArgv, ksOptions, 0); intf->set = 0; intf->bootProto = BOOTPROTO_UNKNOWN; netc->numDns = 0; while ((rc = poptGetNextOpt(optCon)) >= 0) { arg = poptGetOptArg(optCon); logMessage("rc is %c arg is %s", rc, arg); netSet = intfSet = 0; parseAddress = NULL; switch (rc) { case 'b': if (!strcasecmp(arg, "bootp")) intf->bootProto = BOOTPROTO_BOOTP; else if (!strcasecmp(arg, "dhcp")) intf->bootProto = BOOTPROTO_DHCP; else intf->bootProto = BOOTPROTO_STATIC; intf->set |= INTFINFO_HAS_BOOTPROTO; break; case 'g': parseAddress = &netc->gateway; netSet = NETINFO_HAS_GATEWAY; break; case 'i': parseAddress = &intf->ip; intfSet = INTFINFO_HAS_IP; break; case 'n': parseAddress = &netc->dnsServers[netc->numDns++]; netSet = NETINFO_HAS_DNS; break; case 'm': parseAddress = &intf->netmask; intfSet = INTFINFO_HAS_NETMASK; break; } if (parseAddress) { if (!inet_aton(arg, parseAddress)) { newtWinMessage(_("kickstart"), _("Ok"), _("bad ip number in network command: %s"), arg); } else { netc->set |= netSet; intf->set |= intfSet; } } } if (rc < -1) { newtWinMessage(_("kickstart"), _("Ok"), _("bad argument to kickstart network command %s: %s"), poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); } else { poptFreeContext(optCon); } if (!(intf->set & INTFINFO_HAS_BOOTPROTO)) { if (intf->set & INTFINFO_HAS_IP) intf->bootProto = BOOTPROTO_STATIC; else intf->bootProto = BOOTPROTO_BOOTP; intf->set |= INTFINFO_HAS_BOOTPROTO; } intf->manuallySet = intf->set; netc->manuallySet = netc->set; switch (intf->bootProto) { case BOOTPROTO_STATIC: if (!(intf->set & INTFINFO_HAS_IP)) { newtWinMessage(_("Error"), _("Ok"), _("kickstart network " "command is missing ip address")); stage = SETUP_NETWORK_SETUP; } else { setMissingIpInfo(intf); stage = SETUP_NETWORK_DONE; } break; default: stage = SETUP_NETWORK_SETUP; /* do bootp/dhcp */ break; } if ((rc = getAvailableNetDevice(dl, &device))) return rc; intf->set |= INTFINFO_HAS_DEVICE; strcpy(intf->device, device); } while (stage != SETUP_NETWORK_DONE) { switch (stage) { case SETUP_NETWORK_DETECT: if ((rc = getAvailableNetDevice(dl, &device))) return rc; intf->set |= INTFINFO_HAS_DEVICE; strcpy(intf->device, device); stage = SETUP_NETWORK_METHOD; break; case SETUP_NETWORK_METHOD: i = (intf->set & INTFINFO_HAS_BOOTPROTO) ? i = intf->bootProto - 1 : 0; rc = newtWinMenu(_("Boot Protocol"), _("How should the IP information be set? If your " "system administrator gave you an IP address, " "choose static IP."), 50, 0, 10, 3, bootProtocolList, &i, _("Ok"), _("Back"), NULL); if (rc == 2) return INST_CANCEL; if (!(intf->set & INTFINFO_HAS_BOOTPROTO) || (intf->bootProto != (i + 1))) { intf->bootProto = i + 1; intf->set &= ~(INTFINFO_HAS_IP | INTFINFO_HAS_NETMASK | INTFINFO_HAS_BROADCAST | INTFINFO_HAS_NETWORK); intf->set |= INTFINFO_HAS_BOOTPROTO; intf->manuallySet &= ~(INTFINFO_HAS_IP | INTFINFO_HAS_NETMASK | INTFINFO_HAS_BROADCAST | INTFINFO_HAS_NETWORK); intf->manuallySet |= INTFINFO_HAS_BOOTPROTO; netc->manuallySet = netc->set = 0; } stage = SETUP_NETWORK_SETUP; break; case SETUP_NETWORK_SETUP: switch (intf->bootProto) { case BOOTPROTO_BOOTP: case BOOTPROTO_DHCP: if (justConfig) { stage = SETUP_NETWORK_DONE; break; } if (intf->bootProto == BOOTPROTO_DHCP) { winStatus(40, 3, _("DHCP"), _("Sending DHCP request..."), 0); chptr = doDhcp(30, intf, netc, 0); } else { winStatus(40, 3, _("BOOTP"), _("Sending BOOTP request...")); chptr = doBootp(30, intf, netc); } if (chptr) { newtPopWindow(); newtWinMessage(_("Error"), _("Ok"), chptr); stage = SETUP_NETWORK_METHOD; } else { newtPopWindow(); check = INTFINFO_HAS_IP | INTFINFO_HAS_NETWORK | INTFINFO_HAS_NETMASK | INTFINFO_HAS_BROADCAST; if ((intf->set & check) != check) intf->bootProto = BOOTPROTO_STATIC; else stage = SETUP_NETWORK_DONE; } break; case BOOTPROTO_STATIC: if ((rc = getStaticIPInfo(intf, netc))) stage = SETUP_NETWORK_METHOD; /* back */ else stage = SETUP_NETWORK_DONE; break; } case SETUP_NETWORK_DONE: break; } } 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); if (!strlen(data->gw)) { addr.s_addr = htonl(ntohl(broadcast) - 1); newtEntrySet(data->gwEntry, inet_ntoa(addr), 1); } if (!strlen(data->ns)) { addr.s_addr = htonl(ntohl(network) + 1); newtEntrySet(data->nsEntry, inet_ntoa(addr), 1); } } } int writeNetConfig(char * prefix, struct netInfo * netc, struct intfInfo * gwdev, int verbose) { char filename[100]; FILE * f; int i; int which; 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"); if (netc->manuallySet & NETINFO_HAS_HOSTNAME) fprintf(f, "HOSTNAME=%s\n", netc->hostname); else fprintf(f, "HOSTNAME=localhost.localdomain\n"); if (netc->manuallySet & NETINFO_HAS_DOMAIN) fprintf(f, "DOMAINNAME=%s\n", netc->domain); if (gwdev && (netc->manuallySet & NETINFO_HAS_GATEWAY)) { fprintf(f, "GATEWAY=%s\n", inet_ntoa(netc->gateway)); fprintf(f, "GATEWAYDEV=%s\n", gwdev->device); } if (verbose) { if (netc->manuallySet & NETINFO_HAS_DNS) { for (i = 0, which = 0; i < netc->numDns; i++) fprintf(f, "NS%d=%s\n", which++, inet_ntoa(netc->dnsServers[i])); } } fclose(f); return 0; } int writeHosts(char * prefix, struct netInfo * netc, struct intfInfo * intf, int force) { char filename[100]; FILE * f; char * nickname; int i; if (testing) return 1; sprintf(filename, "%s/hosts", prefix); /* if /etc/hosts already exists, don't bother creating one */ if (!force && !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->manuallySet & NETINFO_HAS_HOSTNAME && netc->manuallySet & NETINFO_HAS_DOMAIN) { i = strlen(netc->hostname) - strlen(netc->domain); if (i > 1 && !strcmp(netc->hostname + i, netc->domain) && netc->hostname[i - 1] == '.') { nickname = strdup(netc->hostname); nickname[i - 1] = '\0'; fprintf(f, "%s\t\t%s %s\n", inet_ntoa(intf->ip), netc->hostname, nickname); free(nickname); } else { fprintf(f, "%s\t\t%s\n", inet_ntoa(intf->ip), 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 netInfo * net) { char filename[100]; FILE * f; int i; /* We always write these, even if they were autoconfigured. Otherwise, the reverse name lookup in the install doesn't work. */ if (testing) return 1; sprintf(filename, "%s/resolv.conf", prefix); if (!((net->set & NETINFO_HAS_DOMAIN) || (net->set & NETINFO_HAS_DNS))) { unlink(filename); logMessage("neither domain name nor dns server are configured"); return 0; } f = fopen(filename, "w"); if (!f) { newtWinMessage(_("Error"), _("Cannot create %s: %s\n"), filename, strerror(errno)); return INST_ERROR; } if (net->set & NETINFO_HAS_DOMAIN) fprintf(f, "search %s\n", net->domain); if (net->set & NETINFO_HAS_DNS) { for (i = 0; i < net->numDns; i++) fprintf(f, "nameserver %s\n", inet_ntoa(net->dnsServers[i])); } fclose(f); res_init(); /* reinit the resolver so DNS changes take affect */ return 0; } int writeNetInterfaceConfig(char * prefix, struct intfInfo * intf) { char filename[100]; FILE * f; if (testing) return 0; sprintf(filename, "%s/ifcfg-%s", prefix, intf->device); 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->device); if (intf->bootProto == BOOTPROTO_BOOTP) fprintf(f, "BOOTPROTO=bootp\n"); else if (intf->bootProto == BOOTPROTO_DHCP) fprintf(f, "BOOTPROTO=dhcp\n"); /* Perhaps we should be a bit more carefull about when we write this out? In particular, we aren't passing IP info to the second stage. */ if (intf->manuallySet & INTFINFO_HAS_IP) { fprintf(f, "IPADDR=%s\n", inet_ntoa(intf->ip)); fprintf(f, "NETMASK=%s\n", inet_ntoa(intf->netmask)); fprintf(f, "NETWORK=%s\n", inet_ntoa(intf->network)); fprintf(f, "BROADCAST=%s\n", inet_ntoa(intf->broadcast)); } fprintf(f, "ONBOOT=yes\n"); fclose(f); return 0; } int readNetInterfaceConfig(char * prefix, char * device, struct intfInfo * intf) { FILE * f; char * start, * end; char buf[250]; int line = 0; int got = 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->set = 0; return 0; } } intf->set = INTFINFO_HAS_BOOTPROTO; intf->bootProto = BOOTPROTO_STATIC; 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, &intf->ip); got |= INTFINFO_HAS_IP; } else if (!strncmp("DEVICE=", start, 7)) { start += 7; strcpy(intf->device, start); } else if (!strncmp("BOOTPROTO=bootp", start, 15)) { intf->bootProto = BOOTPROTO_BOOTP; } else if (!strncmp("BOOTPROTO=dhcp", start, 15)) { intf->bootProto = BOOTPROTO_DHCP; } else if (!strncmp("NETMASK=", start, 8)) { start += 8; inet_aton(start, (struct in_addr *) &intf->netmask); got |= INTFINFO_HAS_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; got |= INTFINFO_HAS_NETWORK; } else if (!strncmp("BROADCAST=", start, 10)) { start += 10; inet_aton(start, (struct in_addr *) &intf->broadcast); got |= INTFINFO_HAS_BROADCAST; } } intf->set |= got; intf->manuallySet |= got; if (intf->set & INTFINFO_HAS_BOOTPROTO) intf->isUp = 1; fclose(f); /* if (intf->bootProto == BOOTPROTO_DHCP) { memset(&intfFoo, 0, sizeof(intfFoo)); memset(&netFoo, 0, sizeof(netFoo)); winStatus(40, 3, _("DHCP"), _("Confirming DHCP server address..."), 0); while (doDhcp(60, &intfFoo, &netFoo, 1)) { newtWinMessage(_("Error"), _("Retry"), _("I can't find your DHCP server! I can't continue " "the install until I do.")); } newtPopWindow(); } */ return 0; } /* Assumes that intf is already configured, and gets netc setup appropriately. Tries a DNS name lookup first, prompts if that fails. o This routine is Kickstart Approved (tm). */ static int configureNetwork(struct netInfo * currNetc, struct intfInfo * currIntf, struct netInfo * netc, struct intfInfo * intf, int justConfig, int dir) { struct netconfig_s n; int top = 3; newtComponent f, okay, back, answer, text; newtGrid buttons, grid, subgrid; int i; int haveBoth, haveEitherManually; int defResult = dir > 0 ? 0 : INST_CANCEL; if (!(intf->set & INTFINFO_HAS_BOOTPROTO)) { logMessage("Ack! HAS_BOOTPROTO isn't set!"); return 1; } if (justConfig && (intf->bootProto != BOOTPROTO_STATIC)) return defResult; haveEitherManually = (netc->manuallySet & NETINFO_HAS_HOSTNAME) || (netc->manuallySet & NETINFO_HAS_DOMAIN); haveBoth = (netc->set & NETINFO_HAS_HOSTNAME) && (netc->set & NETINFO_HAS_DOMAIN); /* If we already have the hostname and domainname, and neither was manually set, we don't need to do anything. */ if (haveBoth && !haveEitherManually) return defResult; if (!haveEitherManually && !guessHostname(currIntf, currNetc, intf, netc) && expert) { logMessage("reverse name lookup worked; skipping hostname config"); return defResult; } haveBoth = (netc->set & NETINFO_HAS_HOSTNAME) && (netc->set & NETINFO_HAS_DOMAIN); if (kickstart && !haveBoth) { newtWinMessage(_("Hostname Lookup"), _("Ok"), _("I cannot automatically determine the hostname. Press " "to enter hostname information.")); } else if (haveBoth && !haveEitherManually && !expert) { return defResult; } text = newtTextboxReflowed(-1, -1, _("Please enter your domain name, host name, and the IP " "addresses of any additional nameservers. Your host name " "should be a fully-qualified host name, such as " "mybox.mylab.myco.com. If you don't have any additional " "nameservers, leave the nameserver entries blank."), 50, 5, 10, 0); subgrid = newtCreateGrid(2, 4); newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT, newtLabel(1, top, _("Domain name:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT, newtLabel(1, top + 1, _("Host name:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT, newtLabel(1, top + 2, _("Secondary nameserver (IP):")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 3, NEWT_GRID_COMPONENT, newtLabel(1, top + 3, _("Tertiary nameserver (IP):")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); 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); newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, n.dnEntry, 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, n.hnEntry, 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 2, NEWT_GRID_COMPONENT, n.nsEntrys[1], 1, 0, 0, 0, 0, 0); newtGridSetField(subgrid, 1, 3, NEWT_GRID_COMPONENT, n.nsEntrys[2], 1, 0, 0, 0, 0, 0); if (!(netc->set & NETINFO_HAS_DNS)) { newtEntrySetFlags(n.nsEntrys[1], NEWT_FLAG_DISABLED, NEWT_FLAGS_SET); newtEntrySetFlags(n.nsEntrys[2], NEWT_FLAG_DISABLED, NEWT_FLAGS_SET); } buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &back, NULL); grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid, 0, 1, 0, 1, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); if (netc->set & NETINFO_HAS_HOSTNAME) newtEntrySet(n.hnEntry, netc->hostname, 0); if (netc->set & NETINFO_HAS_DOMAIN) newtEntrySet(n.dnEntry, netc->domain, 0); if (netc->numDns >= 2) { newtEntrySet(n.nsEntrys[1], inet_ntoa(netc->dnsServers[1]), 0); if (netc->numDns >= 3) newtEntrySet(n.nsEntrys[2], inet_ntoa(netc->dnsServers[2]), 0); } newtComponentAddCallback(n.dnEntry, hnCallback, &n); f = newtForm(NULL, NULL, 0); newtGridAddComponentsToForm(grid, f, 1); newtGridWrappedWindow(grid, _("Configure Network")); newtGridFree(grid, 1); answer = newtRunForm(f); if (!(netc->set & NETINFO_HAS_HOSTNAME) || (strlen(n.hn) && strcmp(netc->hostname, n.hn))) { if (netc->hostname) free(netc->hostname); netc->hostname = strdup(n.hn); netc->set |= NETINFO_HAS_HOSTNAME; netc->manuallySet |= NETINFO_HAS_HOSTNAME; } if (!(netc->set & NETINFO_HAS_DOMAIN) || (strlen(n.dn) && strcmp(netc->domain, n.dn))) { if (netc->domain) free(netc->domain); netc->domain = strdup(n.dn); netc->set |= NETINFO_HAS_DOMAIN; netc->manuallySet |= NETINFO_HAS_DOMAIN; } if (netc->set & NETINFO_HAS_DNS) { for (i = 1; i < 3; i++) { if (*n.ns[i] && strlen(n.ns[i])) { inet_aton(n.ns[i], &netc->dnsServers[i]); netc->numDns = i + 1; } } } newtFormDestroy(f); newtPopWindow(); if (answer == back) return INST_CANCEL; return 0; } int readNetConfig(char * prefix, struct netInfo * netc) { FILE * f; char * start, * end; char buf[250]; int line = 0; int got = 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 { 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; if (strcmp(start, "localhost.localdomain")) { if (netc->hostname) free(netc->hostname); netc->hostname = strdup(start); got |= NETINFO_HAS_HOSTNAME; } } else if (!strncmp("DOMAINNAME=", start, 11)) { start += 11; if (netc->domain) free(netc->domain); netc->domain = strdup(start); got |= NETINFO_HAS_DOMAIN; } else if (!strncmp("GATEWAY=", start, 8)) { start += 8; inet_aton(start, &netc->gateway); got |= NETINFO_HAS_GATEWAY; } else if (!strncmp("NS0=", start, 4)) { start += 4; inet_aton(start, &netc->dnsServers[0]); netc->numDns++; } else if (!strncmp("NS1=", start, 4)) { start += 4; inet_aton(start, &netc->dnsServers[1]); netc->numDns++; } else if (!strncmp("NS2=", start, 4)) { start += 4; inet_aton(start, &netc->dnsServers[2]); netc->numDns++; } } fclose(f); if (netc->numDns) got |= NETINFO_HAS_DNS; netc->set |= got; netc->manuallySet |= got; return 0; } int bringUpNetworking(struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, int dir) { return doBringUpNetworking(intf, netc, intf, netc, dl, dir, 0); } static int doBringUpNetworking(struct intfInfo * currIntf, struct netInfo * currNetc, struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, int dir, int justConfig) { enum { BRINGUP_NET, BRINGUP_CONF, BRINGUP_DONE} step; int rc; struct intfInfo loopback; if (dir > 0) step = BRINGUP_NET; else step = BRINGUP_CONF; while (step != BRINGUP_DONE) { switch (step) { case BRINGUP_NET: rc = setupNetworkInterface(intf, netc, dl, justConfig, dir); if (rc) return rc; step = BRINGUP_CONF, dir = 1; break; case BRINGUP_CONF: rc = configureNetwork(currNetc, currIntf, netc, intf, justConfig, dir); if (rc == INST_CANCEL) step = BRINGUP_NET, dir = -1; else if (rc) return INST_ERROR; else step = BRINGUP_DONE; break; case BRINGUP_DONE: break; } } /* write out the /etc/resolv.conf, as we'll need that to use name services properly */ writeResolvConf("/etc", netc); /* configure loopback device */ strcpy(loopback.device,"lo"); loopback.isPtp=0; loopback.isUp=0; loopback.ip.s_addr=htonl(0x7f000001); loopback.netmask.s_addr=htonl(0xff000000); loopback.broadcast.s_addr=htonl(0x7fffffff); loopback.network.s_addr=htonl(0x7f000000); configureNetDevice(&loopback); return 0; } #define CHECKNET_CONFIG 1 #define CHECKNET_KEEP 2 #define CHECKNET_NONE 3 static int checkNetConfigPanel(struct intfInfo * intf, int * choice) { char * choices[] = { N_("Keep the current IP configuration"), N_("Reconfigure network now"), N_("Don't set up networking"), NULL }; char ** chptrptr; int item = 0; int rc; for (chptrptr = choices; *chptrptr; chptrptr++) *chptrptr = _(*chptrptr); if (kickstart) { /* FIXME: we need to let the ks file set this stuff up even if we did a cdrom install */ *choice = CHECKNET_KEEP; return 0; } if (intf->set & INTFINFO_HAS_BOOTPROTO) { rc = newtWinMenu(_("Network Configuration"), _("LAN networking has already been configured. Do you " "want to:"), 40, 5, 10, 3, choices, &item, _("Ok"), NULL); /* _("Back"), NULL);*/ /*if (rc == 2) return INST_CANCEL;*/ switch (item) { case 0: *choice = CHECKNET_KEEP; break; case 1: *choice = CHECKNET_CONFIG; break; case 2: *choice = CHECKNET_NONE; break; } } else { rc = newtWinTernary(_("Network Configuration"), _("Yes"), _("No"), _("Back"), _("Do you want to configure LAN (not dialup) " "networking for your installed system?"), NULL); if (rc == 1 || !rc) { *choice = CHECKNET_CONFIG; } else if (rc == 3) { return INST_CANCEL; } else { *choice = CHECKNET_NONE; } } return 0; } int checkNetConfig(struct intfInfo * intf, struct netInfo * netc, struct intfInfo * intfFinal, struct netInfo * netcFinal, struct driversLoaded ** dl, int dir) { int choice = CHECKNET_CONFIG, rc; static int lastKept = 0; int stage = (dir > 0 || lastKept || !intfFinal->set) ? 1 : 2; if (kickstart) { if (intf->set & INTFINFO_HAS_BOOTPROTO) { *intfFinal = *intf; *netcFinal = *netc; return INST_OKAY; } else { if (!ksHasCommand(KS_CMD_NETWORK)) return INST_OKAY; return doBringUpNetworking(intf, netc, intfFinal, netcFinal, dl, dir, 1); } } /* FIXME: this doesn't handle cancel very well as the dl makes it difficult :-( */ while (stage < 3) { switch (stage) { case 1: rc = checkNetConfigPanel(intf, &choice); if (rc) return rc; stage = 2, dir = 1; break; case 2: lastKept = 0; switch (choice) { case CHECKNET_CONFIG: rc = doBringUpNetworking(intf, netc, intfFinal, netcFinal, dl, dir, 1); if (rc == INST_ERROR) return rc; else if (rc == INST_CANCEL) dir = -1; else dir = 1; stage += dir; break; case CHECKNET_KEEP: *intfFinal = *intf; *netcFinal = *netc; stage += dir; lastKept = 1; break; case CHECKNET_NONE: intfFinal->set = netcFinal->set = 0; stage = 3; break; } break; } } return 0; }