tcpip.c revision 188631
138061Smsmith/* 238061Smsmith * $FreeBSD: head/usr.sbin/sysinstall/tcpip.c 188631 2009-02-15 03:10:20Z imp $ 338061Smsmith * 438061Smsmith * Copyright (c) 1995 538061Smsmith * Gary J Palmer. All rights reserved. 638061Smsmith * Copyright (c) 1996 738061Smsmith * Jordan K. Hubbard. All rights reserved. 838061Smsmith * 938061Smsmith * Redistribution and use in source and binary forms, with or without 1038061Smsmith * modification, are permitted provided that the following conditions 1138061Smsmith * are met: 1238061Smsmith * 1. Redistributions of source code must retain the above copyright 1338061Smsmith * notice, this list of conditions and the following disclaimer, 1438061Smsmith * verbatim and that no modifications are made prior to this 1538061Smsmith * point in the file. 1638061Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1738061Smsmith * notice, this list of conditions and the following disclaimer in the 1838061Smsmith * documentation and/or other materials provided with the distribution. 1938061Smsmith * 2038061Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2138061Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2238061Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2338061Smsmith * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2438061Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2538061Smsmith * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2638061Smsmith * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2738061Smsmith * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 2838061Smsmith * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29119418Sobrien * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30119418Sobrien * 31119418Sobrien */ 3238061Smsmith 3338061Smsmith/* 3438061Smsmith * All kinds of hacking also performed by jkh on this code. Don't 3538061Smsmith * blame Gary for every bogosity you see here.. :-) 3638061Smsmith * 3738061Smsmith * -jkh 3838061Smsmith */ 3938061Smsmith 40108470Sschweikh#include "sysinstall.h" 4138061Smsmith#include <sys/param.h> 4238061Smsmith#include <sys/sysctl.h> 4338061Smsmith#include <sys/socket.h> 4438061Smsmith#include <netinet/in.h> 4538061Smsmith#include <netdb.h> 4638061Smsmith#include <paths.h> 4738061Smsmith 4838061Smsmith/* The help file for the TCP/IP setup screen */ 4938061Smsmith#define TCP_HELPFILE "tcp" 5038061Smsmith 5138061Smsmith/* These are nasty, but they make the layout structure a lot easier ... */ 5238061Smsmith 5338061Smsmithstatic char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], 5438061Smsmith gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; 5538061Smsmithstatic int okbutton, cancelbutton; 5638061Smsmithstatic char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; 5738061Smsmithstatic char ipv6addr[INET6_ADDRSTRLEN]; 5838061Smsmith 5938061Smsmith/* What the screen size is meant to be */ 6038061Smsmith#define TCP_DIALOG_Y 0 6138061Smsmith#define TCP_DIALOG_X 8 6238061Smsmith#define TCP_DIALOG_WIDTH COLS - 16 6338061Smsmith#define TCP_DIALOG_HEIGHT LINES - 2 6438061Smsmith 6538061Smsmithstatic Layout layout[] = { 6638061Smsmith#define LAYOUT_HOSTNAME 0 6738061Smsmith { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, 6838061Smsmith "Host:", "Your fully-qualified hostname, e.g. foo.bar.com", 6938061Smsmith hostname, STRINGOBJ, NULL }, 7038061Smsmith#define LAYOUT_DOMAINNAME 1 7138061Smsmith { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, 7238061Smsmith "Domain:", 7338061Smsmith "The name of the domain that your machine is in, e.g. bar.com", 7438061Smsmith domainname, STRINGOBJ, NULL }, 7538061Smsmith#define LAYOUT_GATEWAY 2 7638061Smsmith { 5, 2, 18, IPADDR_FIELD_LEN - 1, 7738061Smsmith "IPv4 Gateway:", 7838061Smsmith "IPv4 address of host forwarding packets to non-local destinations", 7938061Smsmith gateway, STRINGOBJ, NULL }, 8038061Smsmith#define LAYOUT_NAMESERVER 3 8138061Smsmith { 5, 35, 18, INET6_ADDRSTRLEN - 1, 8238061Smsmith "Name server:", "IPv4 or IPv6 address of your local DNS server", 8355939Snsouch nameserver, STRINGOBJ, NULL }, 8455939Snsouch#define LAYOUT_IPADDR 4 8538061Smsmith { 10, 10, 18, IPADDR_FIELD_LEN - 1, 8638061Smsmith "IPv4 Address:", 8755939Snsouch "The IPv4 address to be used for this interface", 8855939Snsouch ipaddr, STRINGOBJ, NULL }, 8938061Smsmith#define LAYOUT_NETMASK 5 9038061Smsmith { 10, 35, 18, IPADDR_FIELD_LEN - 1, 9138061Smsmith "Netmask:", 9238061Smsmith "The netmask for this interface, e.g. 0xffffff00 for a class C network", 9338061Smsmith netmask, STRINGOBJ, NULL }, 9438061Smsmith#define LAYOUT_EXTRAS 6 9555939Snsouch { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, 9655939Snsouch "Extra options to ifconfig (usually empty):", 9755939Snsouch "Any interface-specific options to ifconfig you would like to add", 9855939Snsouch extras, STRINGOBJ, NULL }, 9938061Smsmith#define LAYOUT_OKBUTTON 7 10038061Smsmith { 19, 15, 0, 0, 10138061Smsmith "OK", "Select this if you are happy with these settings", 10238061Smsmith &okbutton, BUTTONOBJ, NULL }, 10338061Smsmith#define LAYOUT_CANCELBUTTON 8 10438061Smsmith { 19, 35, 0, 0, 10538061Smsmith "CANCEL", "Select this if you wish to cancel this screen", 10638061Smsmith &cancelbutton, BUTTONOBJ, NULL }, 10738061Smsmith LAYOUT_END, 10838061Smsmith}; 10955939Snsouch 11055939Snsouch#define _validByte(b) ((b) >= 0 && (b) <= 255) 11138061Smsmith 11238061Smsmith/* whine */ 11338061Smsmithstatic void 11438061Smsmithfeepout(char *msg) 11538061Smsmith{ 11638061Smsmith beep(); 11738061Smsmith msgConfirm("%s", msg); 11838061Smsmith} 11938061Smsmith 12038061Smsmith/* Verify IP address integrity */ 12138061Smsmithstatic int 12238061SmsmithverifyIP(char *ip, unsigned long *mask, unsigned long *out) 12338061Smsmith{ 12438061Smsmith long a, b, c, d; 12538061Smsmith char *endptr, *endptr_prev; 12638061Smsmith 12738061Smsmith unsigned long parsedip; 12838061Smsmith unsigned long max_addr = (255 << 24) | (255 << 16) | (255 << 8) | 255; 12938061Smsmith 13038061Smsmith if (ip == NULL) 13138061Smsmith return 0; 13238061Smsmith a = strtol(ip, &endptr, 10); 13338061Smsmith if (endptr - ip == 0 || *endptr++ != '.') 13438061Smsmith return 0; 13538061Smsmith endptr_prev = endptr; 13638061Smsmith b = strtol(endptr, &endptr, 10); 13738061Smsmith if (endptr - endptr_prev == 0 || *endptr++ != '.') 13838061Smsmith return 0; 13938061Smsmith endptr_prev = endptr; 14038061Smsmith c = strtol(endptr, &endptr, 10); 14143433Snsouch if (endptr - endptr_prev == 0 || *endptr++ != '.') 14243433Snsouch return 0; 14338061Smsmith endptr_prev = endptr; 14443433Snsouch d = strtol(endptr, &endptr, 10); 14543433Snsouch if (*endptr != '\0' || endptr - endptr_prev == 0) 14638061Smsmith return 0; 14738061Smsmith if (!_validByte(a) || !_validByte(b) || !_validByte(c) || !_validByte(d)) 14855939Snsouch return 0; 149147256Sbrooks parsedip = (a << 24) | (b << 16) | (c << 8) | d; 15038061Smsmith if (out) 15138061Smsmith *out = parsedip; 15255939Snsouch /* 15355939Snsouch * The ip address must not be network or broadcast address. 15438061Smsmith */ 15538061Smsmith if (mask && ((parsedip == (parsedip & *mask)) || 15638061Smsmith (parsedip == ((parsedip & *mask) + max_addr - *mask)))) 15738061Smsmith return 0; 15838061Smsmith return 1; 15938061Smsmith} 16038061Smsmith 16138061Smsmithstatic int 16238061SmsmithverifyIP6(char *ip) 16338061Smsmith{ 16438061Smsmith struct addrinfo hints, *res; 16538061Smsmith 16638061Smsmith memset(&hints, 0, sizeof(hints)); 16738061Smsmith hints.ai_family = AF_INET6; 16838061Smsmith hints.ai_socktype = SOCK_STREAM; 16938061Smsmith hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 17038061Smsmith if (getaddrinfo(ip, NULL, &hints, &res) == 0) { 17138061Smsmith freeaddrinfo(res); 17255939Snsouch return 1; 17338061Smsmith } 17455939Snsouch return 0; 17555939Snsouch} 17655939Snsouch 17755939Snsouch/* Verify IPv4 netmask as being well-formed as 17855939Snsouch a 0x or AAA.BBB.CCC.DDD mask */ 17955939Snsouchstatic int 18038061SmsmithverifyNetmask(const char *netmask, unsigned long *out) 18155939Snsouch{ 18255939Snsouch unsigned long mask; 18356455Speter long tmp; 18456455Speter char *endptr; 18556455Speter 186127189Sguido if (netmask[0] == '0' && (netmask[1] == 'x' || netmask[1] == 'X')) { 18755939Snsouch /* Parse out hex mask */ 188127189Sguido mask = strtoul(netmask, &endptr, 0); 189127189Sguido if (*endptr != '\0') 190127189Sguido return 0; 19156455Speter } else { 19238061Smsmith /* Parse out quad decimal mask */ 19338061Smsmith tmp = strtoul(netmask, &endptr, 10); 19438061Smsmith if (!_validByte(tmp) || *endptr++ != '.') 19555939Snsouch return 0; 19655939Snsouch mask = tmp; 19738061Smsmith tmp = strtoul(endptr, &endptr, 10); 19855939Snsouch if (!_validByte(tmp) || *endptr++ != '.') 19955939Snsouch return 0; 20056618Sdfr mask = (mask << 8) + tmp; 20157177Speter tmp = strtoul(endptr, &endptr, 10); 20238061Smsmith if (!_validByte(tmp) || *endptr++ != '.') 20355939Snsouch return 0; 20455939Snsouch mask = (mask << 8) + tmp; 20555939Snsouch tmp = strtoul(endptr, &endptr, 10); 20655939Snsouch if (!_validByte(tmp) || *endptr++ != '\0') 20755939Snsouch return 0; 20838061Smsmith mask = (mask << 8) + tmp; 20955939Snsouch } 21055939Snsouch /* Verify that we have a continous netmask */ 21155939Snsouch if ((((-mask & mask) - 1) | mask) != 0xffffffff) 21243989Snsouch return 0; 21338061Smsmith if (out) 21455939Snsouch *out = mask; 21555939Snsouch return 1; 21655939Snsouch} 21755939Snsouch 21855939Snsouchstatic int 21955939SnsouchverifyGW(char *gw, unsigned long *ip, unsigned long *mask) 22038061Smsmith{ 22138061Smsmith unsigned long parsedgw; 22238061Smsmith 22338061Smsmith if (!verifyIP(gw, mask, &parsedgw)) 22438061Smsmith return 0; 22538061Smsmith /* Gateway needs to be within the set of IPs reachable through the 22655939Snsouch interface */ 22738061Smsmith if (ip && mask && ((parsedgw & *mask) != (*ip & *mask))) 22855939Snsouch return 0; 22938061Smsmith return 1; 23038061Smsmith} 23138061Smsmith 23255939Snsouch/* Check for the settings on the screen - the per-interface stuff is 23338061Smsmith moved to the main handling code now to do it on the fly - sigh */ 23455939Snsouchstatic int 235147256SbrooksverifySettings(void) 23638061Smsmith{ 237147256Sbrooks unsigned long parsedip; 238147256Sbrooks unsigned long parsednetmask; 239147256Sbrooks 240147256Sbrooks if (!hostname[0]) 241147256Sbrooks feepout("Must specify a host name of some sort!"); 24255939Snsouch else if (netmask[0] && !verifyNetmask(netmask, &parsednetmask)) 243121816Sbrooks feepout("Invalid netmask value"); 24438061Smsmith else if (nameserver[0] && !verifyIP(nameserver, NULL, NULL) && 245133695Srwatson !verifyIP6(nameserver)) 246133695Srwatson feepout("Invalid name server IP address specified"); 24738061Smsmith else if (ipaddr[0] && !verifyIP(ipaddr, &parsednetmask, &parsedip)) 24838061Smsmith feepout("Invalid IPv4 address"); 24938061Smsmith else if (gateway[0] && strcmp(gateway, "NO") && 25038061Smsmith !verifyGW(gateway, ipaddr[0] ? &parsedip : NULL, 25138061Smsmith netmask[0] ? &parsednetmask : NULL)) 25238061Smsmith feepout("Invalid gateway IPv4 address specified"); 25338061Smsmith else 25443773Sdes return 1; 25538061Smsmith return 0; 25655939Snsouch} 25738061Smsmith 25838061Smsmithstatic void 25938061SmsmithdhcpGetInfo(Device *devp) 26038061Smsmith{ 26138061Smsmith char leasefile[PATH_MAX]; 26238061Smsmith 26338061Smsmith snprintf(leasefile, sizeof(leasefile), "%sdhclient.leases.%s", 26438061Smsmith _PATH_VARDB, devp->name); 26538061Smsmith /* If it fails, do it the old-fashioned way */ 26638061Smsmith if (dhcpParseLeases(leasefile, hostname, domainname, 26738061Smsmith nameserver, ipaddr, gateway, netmask) == -1) { 26838061Smsmith FILE *ifp; 26938061Smsmith char *cp, cmd[256], data[2048]; 27038061Smsmith int i, j; 27138061Smsmith 27238061Smsmith /* Bah, now we have to kludge getting the information from ifconfig */ 27338061Smsmith snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 27438061Smsmith ifp = popen(cmd, "r"); 27538061Smsmith if (ifp) { 27638061Smsmith j = fread(data, 1, sizeof(data), ifp); 27738061Smsmith fclose(ifp); 27838061Smsmith if (j < 0) /* paranoia */ 27938061Smsmith j = 0; 28038061Smsmith data[j] = '\0'; 28138061Smsmith if (isDebug()) 28238061Smsmith msgDebug("DHCP configured interface returns %s\n", data); 28338061Smsmith /* XXX This is gross as it assumes a certain ordering to 28438061Smsmith ifconfig's output! XXX */ 28538061Smsmith if ((cp = strstr(data, "inet ")) != NULL) { 28638061Smsmith i = 0; 28738061Smsmith cp += 5; /* move over keyword */ 28838061Smsmith while (*cp != ' ') 28938061Smsmith ipaddr[i++] = *(cp++); 29038061Smsmith ipaddr[i] = '\0'; 29138061Smsmith if (!strncmp(++cp, "netmask", 7)) { 29238061Smsmith i = 0; 29338061Smsmith cp += 8; 29438061Smsmith while (*cp != ' ') 29538061Smsmith netmask[i++] = *(cp++); 29638061Smsmith netmask[i] = '\0'; 29738061Smsmith } 29838061Smsmith } 29938061Smsmith } 30038061Smsmith } 30138061Smsmith 30238061Smsmith /* If we didn't get a name server value, hunt for it in resolv.conf */ 30338061Smsmith if (!nameserver[0] && file_readable("/etc/resolv.conf")) 304121816Sbrooks configEnvironmentResolv("/etc/resolv.conf"); 30555939Snsouch if (hostname[0]) 30655939Snsouch variable_set2(VAR_HOSTNAME, hostname, 0); 30738061Smsmith} 30838061Smsmith 30938061Smsmithstatic void 31055939SnsouchrtsolGetInfo(Device *devp) 31138061Smsmith{ 31238061Smsmith FILE *ifp; 31338061Smsmith char *cp, cmd[256], data[2048]; 31438061Smsmith int i; 31538061Smsmith 31638061Smsmith snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 31738061Smsmith if ((ifp = popen(cmd, "r")) == NULL) 31838061Smsmith return; 31938061Smsmith while (fgets(data, sizeof(data), ifp) != NULL) { 32038061Smsmith if (isDebug()) 32138061Smsmith msgDebug("RTSOL configured interface returns %s\n", data); 32238061Smsmith if ((cp = strstr(data, "inet6 ")) != NULL) { 32338061Smsmith cp += 6; /* move over keyword */ 32438061Smsmith if (strncmp(cp, "fe80:", 5)) { 32538061Smsmith i = 0; 32655939Snsouch while (*cp != ' ') 32738061Smsmith ipv6addr[i++] = *(cp++); 32838061Smsmith ipv6addr[i] = '\0'; 32938061Smsmith } 33055939Snsouch } 33138061Smsmith } 33238061Smsmith fclose(ifp); 33338061Smsmith} 33438061Smsmith 33542443Snsouch/* This is it - how to get TCP setup values */ 33638061Smsmithint 33738061SmsmithtcpOpenDialog(Device *devp) 33855939Snsouch{ 33938061Smsmith WINDOW *ds_win, *save = NULL; 34038061Smsmith ComposeObj *obj = NULL; 34142443Snsouch int n = 0, filled = 0, cancel = FALSE; 34242443Snsouch int max, ret = DITEM_SUCCESS; 34355939Snsouch int use_dhcp = FALSE; 34442443Snsouch int use_rtsol = FALSE; 34538061Smsmith char *tmp; 34655939Snsouch char title[80]; 34738061Smsmith 34838061Smsmith save = savescr(); 34938061Smsmith /* Initialise vars from previous device values */ 350147256Sbrooks if (devp->private) { 351111119Simp DevInfo *di = (DevInfo *)devp->private; 35238061Smsmith 35355939Snsouch SAFE_STRCPY(ipaddr, di->ipaddr); 35438061Smsmith SAFE_STRCPY(netmask, di->netmask); 35538061Smsmith SAFE_STRCPY(extras, di->extras); 35638061Smsmith use_dhcp = di->use_dhcp; 35755939Snsouch use_rtsol = di->use_rtsol; 35855939Snsouch } 35955939Snsouch else { /* See if there are any defaults */ 36055939Snsouch char *cp; 36155939Snsouch char *old_interactive = NULL; 36255939Snsouch 36355939Snsouch /* 36455939Snsouch * This is a hack so that the dialogs below are interactive in a 36538061Smsmith * script if we have requested interactive behavior. 36638061Smsmith */ 36738061Smsmith if (variable_get(VAR_NONINTERACTIVE) && 36838061Smsmith variable_get(VAR_NETINTERACTIVE)) { 36938061Smsmith old_interactive = strdup(VAR_NONINTERACTIVE); 37038061Smsmith variable_unset(VAR_NONINTERACTIVE); 37138061Smsmith } 37238061Smsmith 37338061Smsmith 37438061Smsmith /* 37538061Smsmith * Try a RTSOL scan if such behavior is desired. 37638061Smsmith * If the variable was configured and is YES, do it. 37738061Smsmith * If it was configured to anything else, treat it as NO. 378147256Sbrooks * Otherwise, ask the question interactively. 37938061Smsmith */ 38038061Smsmith if (!variable_get(VAR_NO_INET6) && 38138061Smsmith (!variable_cmp(VAR_TRY_RTSOL, "YES") || 382147256Sbrooks (variable_get(VAR_TRY_RTSOL)==0 && !msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { 38338061Smsmith int i; 38438061Smsmith size_t len; 38538061Smsmith 38638061Smsmith i = 0; 38738061Smsmith sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); 38838061Smsmith i = 1; 38938061Smsmith sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); 39038061Smsmith vsystem("ifconfig %s up", devp->name); 39138061Smsmith len = sizeof(i); 39238061Smsmith sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 39338061Smsmith sleep(i + 1); 39438061Smsmith Mkdir("/var/run"); 39538061Smsmith msgNotify("Scanning for RA servers..."); 39638061Smsmith if (0 == vsystem("rtsol %s", devp->name)) { 39738061Smsmith len = sizeof(i); 39838061Smsmith sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 39938061Smsmith sleep(i + 1); 40040626Smsmith rtsolGetInfo(devp); 40140626Smsmith use_rtsol = TRUE; 40240626Smsmith } else 40340626Smsmith use_rtsol = FALSE; 40440626Smsmith } 40540626Smsmith 40640626Smsmith 40738061Smsmith /* 40838373Sbde * First try a DHCP scan if such behavior is desired. 40938061Smsmith * If the variable was configured and is YES, do it. 41038061Smsmith * If it was configured to anything else, treat it as NO. 41138061Smsmith * Otherwise, ask the question interactively. 41238061Smsmith */ 41338061Smsmith if (!variable_cmp(VAR_TRY_DHCP, "YES") || 41438061Smsmith (variable_get(VAR_TRY_DHCP)==0 && !msgNoYes("Do you want to try DHCP configuration of the interface?"))) { 41555939Snsouch Mkdir("/var/db"); 41638061Smsmith Mkdir("/var/run"); 41755939Snsouch Mkdir("/tmp"); 41855939Snsouch msgNotify("Scanning for DHCP servers..."); 41938061Smsmith /* XXX clear any existing lease */ 42038061Smsmith /* XXX limit protocol to N tries */ 42138061Smsmith if (0 == vsystem("dhclient %s", devp->name)) { 42255939Snsouch dhcpGetInfo(devp); 42355939Snsouch use_dhcp = TRUE; 42438061Smsmith } 42538061Smsmith else 42638061Smsmith use_dhcp = FALSE; 42738061Smsmith } 42838061Smsmith 42938061Smsmith /* Restore old VAR_NONINTERACTIVE if needed. */ 43038061Smsmith if (old_interactive != NULL) { 43155939Snsouch variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 43238061Smsmith free(old_interactive); 43342443Snsouch } 43438061Smsmith 43555939Snsouch /* Special hack so it doesn't show up oddly in the tcpip setup menu */ 43638061Smsmith if (!strcmp(gateway, "NO")) 43738061Smsmith gateway[0] = '\0'; 43838061Smsmith 43955939Snsouch /* Get old IP address from variable space, if available */ 44055939Snsouch if (!ipaddr[0]) { 44138061Smsmith if ((cp = variable_get(VAR_IPADDR)) != NULL) 44255939Snsouch SAFE_STRCPY(ipaddr, cp); 44338061Smsmith else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) 44438061Smsmith SAFE_STRCPY(ipaddr, cp); 44538061Smsmith } 44655939Snsouch 44755939Snsouch /* Get old netmask from variable space, if available */ 44838061Smsmith if (!netmask[0]) { 44938061Smsmith if ((cp = variable_get(VAR_NETMASK)) != NULL) 45038061Smsmith SAFE_STRCPY(netmask, cp); 45138061Smsmith else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) 45238061Smsmith SAFE_STRCPY(netmask, cp); 45343773Sdes } 45443773Sdes 45543773Sdes /* Get old extras string from variable space, if available */ 456123922Ssam if (!extras[0]) { 45743773Sdes if ((cp = variable_get(VAR_EXTRAS)) != NULL) 45843773Sdes SAFE_STRCPY(extras, cp); 45943773Sdes else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) 46055939Snsouch SAFE_STRCPY(extras, cp); 46138061Smsmith } 46255939Snsouch } 46355939Snsouch 46455939Snsouch /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ 46538061Smsmith if (!hostname[0]) { 46638061Smsmith tmp = variable_get(VAR_HOSTNAME); 46738061Smsmith if (tmp) 46838061Smsmith SAFE_STRCPY(hostname, tmp); 46938061Smsmith } 47038061Smsmith if (!domainname[0]) { 47138061Smsmith tmp = variable_get(VAR_DOMAINNAME); 472147256Sbrooks if (tmp) 47338061Smsmith SAFE_STRCPY(domainname, tmp); 47438061Smsmith } 47555939Snsouch if (!gateway[0]) { 47638061Smsmith tmp = variable_get(VAR_GATEWAY); 47738061Smsmith if (tmp && strcmp(tmp, "NO")) 47855939Snsouch SAFE_STRCPY(gateway, tmp); 47938061Smsmith } 48038061Smsmith if (!nameserver[0]) { 48138061Smsmith tmp = variable_get(VAR_NAMESERVER); 48255939Snsouch if (tmp) 48338061Smsmith SAFE_STRCPY(nameserver, tmp); 48438061Smsmith } 48538061Smsmith 486147256Sbrooks /* If non-interactive, jump straight over the dialog crap and into config section */ 48738061Smsmith if (variable_get(VAR_NONINTERACTIVE) && 48838061Smsmith !variable_get(VAR_NETINTERACTIVE)) { 48938061Smsmith if (!hostname[0]) 49038061Smsmith msgConfirm("WARNING: hostname variable not set and is a non-optional\n" 49138061Smsmith "parameter. Please add this to your installation script\n" 49255939Snsouch "or set the netInteractive variable (see sysinstall man page)"); 49338061Smsmith else 49438061Smsmith goto netconfig; 49538061Smsmith } 49638061Smsmith 49738061Smsmith /* Now do all the screen I/O */ 49838061Smsmith dialog_clear_norefresh(); 49955939Snsouch 50038061Smsmith /* Modify the help line for PLIP config */ 50138061Smsmith if (!strncmp(devp->name, "plip", 4)) 50238061Smsmith layout[LAYOUT_EXTRAS].help = 50338061Smsmith "For PLIP configuration, you must enter the peer's IP address here."; 50438061Smsmith 50538061Smsmith /* We need a curses window */ 50638061Smsmith tmp = " Network Configuration "; 50738061Smsmith if (ipv6addr[0]) 50838061Smsmith tmp = string_concat(tmp, "(IPv6 ready) "); 50938061Smsmith if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, 51038061Smsmith TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { 511147256Sbrooks beep(); 512147256Sbrooks msgConfirm("Cannot open TCP/IP dialog window!!"); 513147256Sbrooks restorescr(save); 51438061Smsmith return DITEM_FAILURE; 515147256Sbrooks } 516147256Sbrooks 517134391Sandre /* Draw interface configuration box */ 51838061Smsmith draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, 51938061Smsmith dialog_attr, border_attr); 52038061Smsmith wattrset(ds_win, dialog_attr); 52155939Snsouch sprintf(title, " Configuration for Interface %s ", devp->name); 522147256Sbrooks mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); 52338061Smsmith 52438061Smsmith /* Some more initialisation before we go into the main input loop */ 52538061Smsmith obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); 52655939Snsouch 52755939Snsouchreenter: 52838061Smsmith cancelbutton = okbutton = 0; 52938061Smsmith while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { 53055939Snsouch /* Prevent this from being irritating if user really means NO */ 53138061Smsmith if (filled < 3) { 53238061Smsmith /* Insert a default value for the netmask, 0xffffff00 is 53355939Snsouch * the most appropriate one (entire class C, or subnetted 53455939Snsouch * class A/B network). 53538061Smsmith */ 53638061Smsmith if (!netmask[0]) { 53738061Smsmith strcpy(netmask, "255.255.255.0"); 53838061Smsmith RefreshStringObj(layout[LAYOUT_NETMASK].obj); 53955939Snsouch ++filled; 54038061Smsmith } 54155939Snsouch if (!index(hostname, '.') && domainname[0]) { 54238061Smsmith strcat(hostname, "."); 54338061Smsmith strcat(hostname, domainname); 54438061Smsmith RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); 54538061Smsmith ++filled; 54638061Smsmith } 54738061Smsmith else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { 54838061Smsmith SAFE_STRCPY(domainname, tmp + 1); 54938061Smsmith RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); 55038061Smsmith ++filled; 55138061Smsmith } 55238061Smsmith } 55338061Smsmith } 55438061Smsmith if (!cancel && !verifySettings()) 55538061Smsmith goto reenter; 556147256Sbrooks 557147256Sbrooks /* Clear this crap off the screen */ 558147256Sbrooks delwin(ds_win); 55938061Smsmith dialog_clear_norefresh(); 560147256Sbrooks use_helpfile(NULL); 561147256Sbrooks 562134391Sandre /* We actually need to inform the rest of sysinstall about this 56338061Smsmith data now if the user hasn't selected cancel. Save the stuff 56438061Smsmith out to the environment via the variable_set() mechanism */ 56538061Smsmith 56638061Smsmithnetconfig: 56738061Smsmith if (!cancel) { 56855939Snsouch DevInfo *di; 56938061Smsmith char temp[512], ifn[255]; 570147256Sbrooks int ipv4_enable = FALSE; 57138061Smsmith 57238061Smsmith if (hostname[0]) { 57338061Smsmith variable_set2(VAR_HOSTNAME, hostname, 1); 57438061Smsmith sethostname(hostname, strlen(hostname)); 57538061Smsmith } 57638061Smsmith if (domainname[0]) 57738061Smsmith variable_set2(VAR_DOMAINNAME, domainname, 0); 57855939Snsouch if (gateway[0]) 57955939Snsouch variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); 580147256Sbrooks if (nameserver[0]) 58138061Smsmith variable_set2(VAR_NAMESERVER, nameserver, 0); 58238061Smsmith if (ipaddr[0]) 58338061Smsmith variable_set2(VAR_IPADDR, ipaddr, 0); 58438061Smsmith if (ipv6addr[0]) 58538061Smsmith variable_set2(VAR_IPV6ADDR, ipv6addr, 0); 58638061Smsmith 58738061Smsmith if (!devp->private) 58838061Smsmith devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); 58938061Smsmith di = devp->private; 59055939Snsouch SAFE_STRCPY(di->ipaddr, ipaddr); 59138061Smsmith SAFE_STRCPY(di->netmask, netmask); 59255939Snsouch SAFE_STRCPY(di->extras, extras); 59355939Snsouch di->use_dhcp = use_dhcp; 59438061Smsmith di->use_rtsol = use_rtsol; 59538061Smsmith 59655939Snsouch if (use_dhcp || ipaddr[0]) 59755939Snsouch ipv4_enable = TRUE; 59838061Smsmith if (ipv4_enable) { 59938061Smsmith sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); 60038061Smsmith if (use_dhcp) { 60138061Smsmith if (strlen(extras) > 0) 60238061Smsmith sprintf(temp, "DHCP %s", extras); 60338061Smsmith else 60438061Smsmith sprintf(temp, "DHCP"); 60538061Smsmith } else 60638061Smsmith sprintf(temp, "inet %s %s netmask %s", 607121816Sbrooks ipaddr, extras, netmask); 60855939Snsouch variable_set2(ifn, temp, 1); 60938061Smsmith } 61038061Smsmith if (use_rtsol) 61138061Smsmith variable_set2(VAR_IPV6_ENABLE, "YES", 1); 61238061Smsmith if (!use_dhcp) 61338061Smsmith configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ 61443773Sdes ret = DITEM_SUCCESS; 61538061Smsmith } 61638061Smsmith else 61738061Smsmith ret = DITEM_FAILURE; 61838061Smsmith restorescr(save); 61938061Smsmith return ret; 62038061Smsmith} 62138061Smsmith 62238061Smsmithstatic Device *NetDev; 62338061Smsmith 62438061Smsmithstatic int 62555939SnsouchnetHook(dialogMenuItem *self) 62638061Smsmith{ 62738061Smsmith Device **devs; 62838061Smsmith 62955939Snsouch devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); 63038061Smsmith if (devs) { 63155939Snsouch if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) 63238061Smsmith NetDev = devs[0]; 63338061Smsmith else 63438061Smsmith NetDev = NULL; 63538061Smsmith } 63655939Snsouch return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; 63755939Snsouch} 63838061Smsmith 63938061Smsmith/* Get a network device */ 64038061SmsmithDevice * 64138061SmsmithtcpDeviceSelect(void) 64238061Smsmith{ 64338061Smsmith DMenu *menu; 64438061Smsmith Device **devs, *rval; 64538061Smsmith int cnt; 64638061Smsmith 64738061Smsmith devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); 64838061Smsmith cnt = deviceCount(devs); 64938061Smsmith rval = NULL; 65055939Snsouch 65138061Smsmith if (!cnt) { 65255939Snsouch msgConfirm("No network devices available!"); 65338061Smsmith return NULL; 65438061Smsmith } 65538061Smsmith else if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { 65638061Smsmith if (!msgYesNo("Running multi-user, assume that the network is already configured?")) 65755939Snsouch return devs[0]; 65838061Smsmith } 65938061Smsmith if (cnt == 1) { 66038061Smsmith if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) 66138061Smsmith rval = devs[0]; 66255939Snsouch } 66338061Smsmith else if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) { 66455939Snsouch devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); 66538061Smsmith cnt = deviceCount(devs); 66638061Smsmith if (cnt) { 66738061Smsmith if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) 66838061Smsmith rval = devs[0]; 66938061Smsmith } 67038061Smsmith } 67143773Sdes else { 67243773Sdes int status; 67338061Smsmith 67455939Snsouch menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); 67538061Smsmith if (!menu) 67638061Smsmith msgFatal("Unable to create network device menu! Argh!"); 67738061Smsmith status = dmenuOpenSimple(menu, FALSE); 67838061Smsmith free(menu); 67938061Smsmith if (status) 68055939Snsouch rval = NetDev; 68138061Smsmith } 68238061Smsmith return rval; 68338061Smsmith} 68455939Snsouch 68538061Smsmith/* Do it from a menu that doesn't care about status */ 68638061Smsmithint 68738061SmsmithtcpMenuSelect(dialogMenuItem *self) 68838061Smsmith{ 68938061Smsmith Device *tmp; 69038061Smsmith WINDOW *save; 69138061Smsmith 69238061Smsmith variable_set("NETWORK_CONFIGURED=NO",0); 69338061Smsmith tmp = tcpDeviceSelect(); 69438061Smsmith variable_unset("NETWORK_CONFIGURED"); 69543773Sdes save = savescr(); 69643773Sdes if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) 69738061Smsmith if (!DEVICE_INIT(tmp)) 69838061Smsmith msgConfirm("Initialization of %s device failed.", tmp->name); 69938061Smsmith restorescr(save); 70038061Smsmith return DITEM_SUCCESS; 70155939Snsouch} 70238061Smsmith