Get network some interface details by using the relevant ioctls (not

trying to parse the output of ifconfig)
Loop if the user specifies an unsupported media type.
Run ifocnfig to set the media type (any anything else the user typed in)
    before running dhcp to assign an address.
Correctly extract the defualt gateway from output of 'route -n show'
Extract nameserver from resolv.conf without using get_command_out(),
    delete get_command_out().
Fixes (at least) PR install/11880, install/12706
This commit is contained in:
dsl 2004-11-11 22:10:54 +00:00
parent fbed044c7e
commit efe04144e4

View File

@ -1,4 +1,4 @@
/* $NetBSD: net.c,v 1.104 2004/11/11 21:36:23 dsl Exp $ */
/* $NetBSD: net.c,v 1.105 2004/11/11 22:10:54 dsl Exp $ */
/*
* Copyright 1997 Piermont Information Systems Inc.
@ -50,8 +50,10 @@
#include <sys/sysctl.h>
#endif
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_media.h>
#include <arpa/inet.h>
#include "defs.h"
#include "md.h"
@ -90,16 +92,11 @@ static char *url_encode (char *dst, const char *src, const char *ep,
const char *safe_chars,
int encode_leading_slash);
/* Get the list of network interfaces. */
static void get_ifinterface_info (void);
static void write_etc_hosts(FILE *f);
#define DHCLIENT_EX "/sbin/dhclient"
#include <signal.h>
static int config_dhcp(char *);
static void get_command_out(char *, size_t, int, const char *, const char *);
static void get_dhcp_value(char *, size_t, const char *);
#ifdef INET6
@ -293,48 +290,64 @@ get_ifconfig_info(void)
free(textbuf);
}
static int
do_ifreq(struct ifmediareq *ifmr, int cmd)
{
int sock;
int rval;
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == -1)
return -1;
memset(ifmr, 0, sizeof *ifmr);
strncpy(ifmr->ifm_name, net_dev, sizeof ifmr->ifm_name);
rval = ioctl(sock, cmd, ifmr);
close(sock);
return rval;
}
/* Fill in defaults network values for the selected interface */
static void
get_ifinterface_info(void)
{
char *textbuf;
int textsize;
char *t;
char hostname[MAXHOSTNAMELEN + 1];
char *dot;
struct ifmediareq ifmr;
struct sockaddr_in *sa_in = (void *)&((struct ifreq *)&ifmr)->ifr_addr;
int modew;
const char *media_opt;
const char *sep;
/* First look to see if the selected interface is already configured. */
textsize = collect(T_OUTPUT, &textbuf,
"/sbin/ifconfig %s inet 2>/dev/null", net_dev);
if (textsize >= 0) {
(void)strtok(textbuf, " \t\n"); /* ignore interface name */
while ((t = strtok(NULL, " \t\n")) != NULL) {
if (strcmp(t, "inet") == 0) {
t = strtok(NULL, " \t\n");
if (strcmp(t, "0.0.0.0") != 0)
strlcpy(net_ip, t, sizeof(net_ip));
continue;
}
if (strcmp(t, "netmask") == 0) {
t = strtok(NULL, " \t\n");
if (strcmp(t, "0x0") != 0)
strlcpy(net_mask, t, sizeof(net_mask));
continue;
}
if (strcmp(t, "media:") == 0) {
t = strtok(NULL, " \t\n");
/* handle "media: Ethernet manual" */
if (strcmp(t, "Ethernet") == 0)
t = strtok(NULL, " \t\n");
if (strcmp(t, "none") != 0 &&
strcmp(t, "manual") != 0)
strlcpy(net_media, t,
sizeof(net_media));
}
if (do_ifreq(&ifmr, SIOCGIFADDR) == 0 && sa_in->sin_addr.s_addr != 0)
strlcpy(net_ip, inet_ntoa(sa_in->sin_addr), sizeof net_ip);
if (do_ifreq(&ifmr, SIOCGIFNETMASK) == 0 && sa_in->sin_addr.s_addr != 0)
strlcpy(net_mask, inet_ntoa(sa_in->sin_addr), sizeof net_mask);
if (do_ifreq(&ifmr, SIOCGIFMEDIA) == 0) {
/* Get the name of the media word */
modew = ifmr.ifm_current;
strlcpy(net_media, get_media_mode_string(modew),
sizeof net_media);
/* and add any media options */
sep = " mediaopt ";
while ((media_opt = get_media_option_string(&modew)) != NULL) {
strlcat(net_media, sep, sizeof net_media);
strlcat(net_media, media_opt, sizeof net_media);
sep = ",";
}
}
free(textbuf);
#ifdef INET6
}
#ifndef INET6
#define get_if6interface_info()
#else
static void
get_if6interface_info(void)
{
char *textbuf, *t;
int textsize;
textsize = collect(T_OUTPUT, &textbuf,
"/sbin/ifconfig %s inet6 2>/dev/null", net_dev);
if (textsize >= 0) {
@ -359,8 +372,15 @@ get_ifinterface_info(void)
}
}
free(textbuf);
}
#endif
static void
get_host_info(void)
{
char hostname[MAXHOSTNAMELEN + 1];
char *dot;
/* Check host (and domain?) name */
if (gethostname(hostname, sizeof(hostname)) == 0 && hostname[0] != 0) {
hostname[sizeof(hostname) - 1] = 0;
@ -379,7 +399,7 @@ get_ifinterface_info(void)
}
/*
* recombine name parts split in get_ifinterface_info and config_network
* recombine name parts split in get_host_info and config_network
* (common code moved here from write_etc_hosts)
*/
static char *
@ -461,6 +481,7 @@ config_network(void)
char *tp;
char *defname;
const char *prompt;
char *textbuf;
int octet0;
int pass, dhcp_config;
int l;
@ -514,31 +535,79 @@ again:
/* Preload any defaults we can find */
get_ifinterface_info();
get_if6interface_info();
get_host_info();
pass = net_mask[0] == '\0' ? 0 : 1;
/* domain and host */
msg_display(MSG_netinfo);
/* ethernet medium */
if (net_media[0] != '\0')
for (;;) {
msg_prompt_add(MSG_net_media, net_media, net_media,
sizeof net_media);
sizeof net_media);
/*
* ifconfig does not allow media specifiers on IFM_MANUAL
* interfaces. Our UI gives no way to set an option back
* to null-string if it gets accidentally set.
* Check for plausible alternatives.
*/
if (strcmp(net_media, "<default>") == 0 ||
strcmp(net_media, "default") == 0 ||
strcmp(net_media, "<manual>") == 0 ||
strcmp(net_media, "manual") == 0 ||
strcmp(net_media, "<none>") == 0 ||
strcmp(net_media, "none") == 0 ||
strcmp(net_media, " ") == 0) {
*net_media = '\0';
}
if (*net_media == '\0')
break;
/* We must set the media type here - to give dhcp a chance */
if (run_program(0, "/sbin/ifconfig %s media %s",
net_dev, net_media) == 0)
break;
/* Failed to set - output the supported values */
if (collect(T_OUTPUT, &textbuf, "/sbin/ifconfig -m %s |"
"while IFS=; read line;"
" do [ \"$line\" = \"${line#*media}\" ] || echo $line;"
" done", net_dev ) > 0)
msg_display(textbuf);
free(textbuf);
}
/* try a dhcp configuration */
dhcp_config = config_dhcp(net_dev);
if (dhcp_config) {
/* Get newly configured data off interface. */
get_ifinterface_info();
get_if6interface_info();
get_host_info();
net_dhcpconf |= DHCPCONF_IPADDR;
/* run route show and extract data */
get_command_out(net_defroute, sizeof(net_defroute), AF_INET,
"/sbin/route -n show -inet 2>/dev/null", "default");
/* Extract default route from output of 'route -n show' */
if (collect(T_OUTPUT, &textbuf,
"/sbin/route -n show | "
"while read dest gateway flags;"
" do [ \"$dest\" = default ] && {"
" echo $gateway; break; };"
" done" ) > 0)
strlcpy(net_defroute, textbuf, sizeof net_defroute);
free(textbuf);
/* pull nameserver info out of /etc/resolv.conf */
get_command_out(net_namesvr, sizeof(net_namesvr), AF_INET,
"cat /etc/resolv.conf 2> /dev/null", "nameserver");
if (collect(T_OUTPUT, &textbuf,
"cat /etc/resolv.conf 2>/dev/null |"
" while read keyword address rest;"
" do [ \"$keyword\" = nameserver "
" -a \"${address#*:}\" = \"${address}\" ] && {"
" echo $address; break; };"
" done" ) > 0)
strlcpy(net_namesvr, textbuf, sizeof net_namesvr);
free(textbuf);
if (net_namesvr[0] != '\0')
net_dhcpconf |= DHCPCONF_NAMESVR;
@ -549,7 +618,7 @@ again:
/* pull hostname out of leases file */
dhcp_host[0] = 0;
get_dhcp_value(dhcp_host, sizeof(net_host), "hostname");
get_dhcp_value(dhcp_host, sizeof(dhcp_host), "hostname");
if (dhcp_host[0] != '\0') {
net_dhcpconf |= DHCPCONF_HOST;
strlcpy(net_host, dhcp_host, sizeof net_host);
@ -589,7 +658,7 @@ again:
if (!is_v6kernel())
v6config = 0;
else if (v6config) {
process_menu(MENU_yesno, deconst(MSG_Perform_IPv6_autoconfiguration));
process_menu(MENU_noyes, deconst(MSG_Perform_IPv6_autoconfiguration));
v6config = yesno ? 1 : 0;
net_ip6conf |= yesno ? IP6CONF_AUTOHOST : 0;
}
@ -633,11 +702,7 @@ again:
|| net_namesvr6[0] != '\0'
#endif
) {
#ifdef DEBUG
f = fopen("/tmp/resolv.conf", "w");
#else
f = fopen("/etc/resolv.conf", "w");
#endif
if (f == NULL) {
if (logging)
(void)fprintf(logfp,
@ -665,26 +730,6 @@ again:
run_program(0, "/sbin/ifconfig lo0 127.0.0.1");
/*
* ifconfig does not allow media specifiers on IFM_MANUAL interfaces.
* Our UI gives no way to set an option back to null-string if it
* gets accidentally set.
* Check for plausible alternatives.
*/
if (strcmp(net_media, "<default>") == 0 ||
strcmp(net_media, "default") == 0 ||
strcmp(net_media, "<manual>") == 0 ||
strcmp(net_media, "manual") == 0 ||
strcmp(net_media, "<none>") == 0 ||
strcmp(net_media, "none") == 0 ||
strcmp(net_media, " ") == 0) {
*net_media = '\0';
}
if (*net_media != '\0')
run_program(0, "/sbin/ifconfig %s media %s",
net_dev, net_media);
#ifdef INET6
if (v6config) {
init_v6kernel(1);
@ -941,10 +986,8 @@ write_etc_hosts(FILE *f)
void
mnt_net_config(void)
{
char ans[8];
char ifconfig_fn[STRSIZE];
FILE *ifconf = NULL;
const char *yes = msg_string(MSG_Yes);
if (!network_up)
return;
@ -1004,7 +1047,7 @@ mnt_net_config(void)
/*
* Add IPaddr/hostname to /etc/hosts.
* Be careful not to clobber any existing contents.
* Relies on ordered seach of /etc/hosts. XXX YP?
* Relies on ordered search of /etc/hosts. XXX YP?
*/
hosts = target_fopen("/etc/hosts", "a");
if (hosts != 0) {
@ -1067,50 +1110,13 @@ config_dhcp(char *inter)
if (yesno) {
/* spawn off dhclient and wait for parent to exit */
dhcpautoconf = run_program(RUN_DISPLAY | RUN_PROGRESS,
"%s -pf /tmp/dhclient.pid -lf /tmp/dhclient.leases %s",
"%s -q -pf /tmp/dhclnt.pid -lf /tmp/dhclient.leases %s",
DHCLIENT_EX, inter);
return dhcpautoconf ? 0 : 1;
}
return 0;
}
static void
get_command_out(char *targ, size_t l, int af, const char *command,
const char *search)
{
int textsize;
char *textbuf;
const char *t;
#ifndef INET6
struct in_addr in;
#else
struct in6_addr in;
#endif
textsize = collect(T_OUTPUT, &textbuf, command);
if (textsize < 0) {
if (logging)
(void)fprintf(logfp,
"Aborting: Could not run %s.\n", command);
(void)fprintf(stderr, "Could not run ifconfig.");
exit(1);
}
if (textsize >= 0) {
(void)strtok(textbuf, " \t\n"); /* ignore interface name */
while ((t = strtok(NULL, " \t\n")) != NULL) {
if (strcmp(t, search) == 0) {
t = strtok(NULL, " \t\n");
if (inet_pton(af, t, &in) == 1 &&
strcmp(t, "0.0.0.0") != 0) {
strlcpy(targ, t, l);
}
}
}
}
free(textbuf);
return;
}
static void
get_dhcp_value(char *targ, size_t l, const char *line)
{