1 /* $NetBSD: net.c,v 1.122 2009/04/07 11:49:18 joerg Exp $ */
4 * Copyright 1997 Piermont Information Systems Inc.
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Piermont Information Systems Inc.
21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
39 /* net.c -- routines to fetch files off the network. */
48 #include <sys/param.h>
50 #include <sys/statvfs.h>
52 #include <sys/sysctl.h>
54 #include <sys/socket.h>
55 #include <sys/ioctl.h>
56 #include <sys/statvfs.h>
57 #include <netinet/in.h>
59 #include <net/if_media.h>
60 #include <arpa/inet.h>
64 #include "menu_defs.h"
68 #include <sys/resource.h>
69 #include <sys/sysctl.h>
72 /* Access to network information */
73 static char *net_devices
;
75 static char net_dev
[STRSIZE
];
76 static char net_domain
[STRSIZE
];
77 static char net_host
[STRSIZE
];
78 static char net_ip
[SSTRSIZE
];
79 static char net_srv_ip
[SSTRSIZE
];
80 static char net_mask
[SSTRSIZE
];
81 static char net_namesvr
[STRSIZE
];
82 static char net_defroute
[STRSIZE
];
83 static char net_media
[STRSIZE
];
84 static char sl_flags
[STRSIZE
];
85 static int net_dhcpconf
;
86 #define DHCPCONF_IPADDR 0x01
87 #define DHCPCONF_NAMESVR 0x02
88 #define DHCPCONF_HOST 0x04
89 #define DHCPCONF_DOMAIN 0x08
91 static char net_ip6
[STRSIZE
];
92 char net_namesvr6
[STRSIZE
];
93 static int net_ip6conf
;
94 #define IP6CONF_AUTOHOST 0x01
98 /* URL encode unsafe characters. */
100 static char *url_encode (char *dst
, const char *src
, const char *ep
,
101 const char *safe_chars
,
102 int encode_leading_slash
);
104 static void write_etc_hosts(FILE *f
);
106 #define DHCPCD "/sbin/dhcpcd"
108 static int config_dhcp(char *);
109 static void get_dhcp_value(char *, size_t, const char *);
112 static int is_v6kernel (void);
113 static void init_v6kernel (int);
114 static int get_v6wait (void);
118 * URL encode unsafe characters. See RFC 1738.
120 * Copies src string to dst, encoding unsafe or reserved characters
121 * in %hex form as it goes, and returning a pointer to the result.
122 * The result is always a nul-terminated string even if it had to be
123 * truncated to avoid overflowing the available space.
125 * This url_encode() function does not operate on complete URLs, it
126 * operates on strings that make up parts of URLs. For example, in a
127 * URL like "ftp://username:password@host/path", the username, password,
128 * host and path should each be encoded separately before they are
129 * joined together with the punctuation characters.
131 * In most ordinary use, the path portion of a URL does not start with
132 * a slash; the slash is a separator between the host portion and the
133 * path portion, and is dealt with by software outside the url_encode()
134 * function. However, it is valid for url_encode() to be passed a
135 * string that does begin with a slash. For example, the string might
136 * represent a password, or a path part of a URL that the user really
137 * does want to begin with a slash.
139 * len is the length of the destination buffer. The result will be
140 * truncated if necessary to fit in the destination buffer.
142 * safe_chars is a string of characters that should not be encoded. If
143 * safe_chars is non-NULL, any characters in safe_chars as well as any
144 * alphanumeric characters will be copied from src to dst without
145 * encoding. Some potentially useful settings for this parameter are:
147 * NULL Everything is encoded (even alphanumerics)
148 * "" Everything except alphanumerics are encoded
149 * "/" Alphanumerics and '/' remain unencoded
150 * "$-_.+!*'()," Consistent with a strict reading of RFC 1738
151 * "$-_.+!*'(),/" As above, except '/' is not encoded
152 * "-_.+!,/" As above, except shell special characters are encoded
154 * encode_leading_slash is a flag that determines whether or not to
155 * encode a leading slash in a string. If this flag is set, and if the
156 * first character in the src string is '/', then the leading slash will
157 * be encoded (as "%2F"), even if '/' is one of the characters in the
158 * safe_chars string. Note that only the first character of the src
159 * string is affected by this flag, and that leading slashes are never
160 * deleted, but either retained unchanged or encoded.
162 * Unsafe and reserved characters are defined in RFC 1738 section 2.2.
163 * The most important parts are:
165 * The characters ";", "/", "?", ":", "@", "=" and "&" are the
166 * characters which may be reserved for special meaning within a
167 * scheme. No other characters may be reserved within a scheme.
170 * Thus, only alphanumerics, the special characters "$-_.+!*'(),",
171 * and reserved characters used for their reserved purposes may be
172 * used unencoded within a URL.
176 #define RFC1738_SAFE "$-_.+!*'(),"
177 #define RFC1738_SAFE_LESS_SHELL "-_.+!,"
178 #define RFC1738_SAFE_LESS_SHELL_PLUS_SLASH "-_.+!,/"
181 url_encode(char *dst
, const char *src
, const char *ep
,
182 const char *safe_chars
, int encode_leading_slash
)
188 for (; dst
< ep
; src
++) {
192 if (safe_chars
!= NULL
&&
193 (ch
!= '/' || !encode_leading_slash
) &&
194 (isalnum(ch
) || strchr(safe_chars
, ch
))) {
197 /* encode this char */
200 snprintf(dst
, ep
- dst
, "%%%02X", ch
);
203 encode_leading_slash
= 0;
210 static const char *ignored_if_names
[] = {
213 "ipip", /* netinet */
214 "gif", /* netinet6 */
215 "faith", /* netinet6 */
218 "mdecap", /* netinet -- never in IF list (?) XXX */
232 get_ifconfig_info(void)
246 /* Get ifconfig information */
248 textsize
= collect(T_OUTPUT
, &textbuf
, "/sbin/ifconfig -a 2>/dev/null");
252 "Aborting: Could not run ifconfig.\n");
253 (void)fprintf(stderr
, "Could not run ifconfig.");
257 for (t
= textbuf
; t
!= NULL
&& *t
!= 0; t
= nt
) {
258 /* find entry for next interface */
259 for (nt
= t
; (nt
= strchr(nt
, '\n')); ) {
263 if (memcmp(t
, "lo0:", 4) == 0)
264 /* completely ignore loopback interface */
269 /* get interface flags */
270 fl
= strtoul(cp
+ 1, &cp
, 16);
274 for (ignore
= ignored_if_names
; *ignore
!= NULL
; ignore
++) {
275 size_t len
= strlen(*ignore
);
276 if (strncmp(t
, *ignore
, len
) == 0 &&
277 isdigit((unsigned char)t
[len
]))
284 /* This interface might be connected to the server */
288 asprintf(&cp
, "%s%.*s ",
289 net_up
? net_up
: "", (int)(cp
- t
), t
);
297 asprintf(&cp
, "%s%.*s ",
298 net_devices
? net_devices
: "", (int)(cp
- t
), t
);
306 do_ifreq(struct ifmediareq
*ifmr
, unsigned long cmd
)
311 sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
315 memset(ifmr
, 0, sizeof *ifmr
);
316 strncpy(ifmr
->ifm_name
, net_dev
, sizeof ifmr
->ifm_name
);
317 rval
= ioctl(sock
, cmd
, ifmr
);
323 /* Fill in defaults network values for the selected interface */
325 get_ifinterface_info(void)
327 struct ifmediareq ifmr
;
328 struct sockaddr_in
*sa_in
= (void *)&((struct ifreq
*)&ifmr
)->ifr_addr
;
330 const char *media_opt
;
333 if (do_ifreq(&ifmr
, SIOCGIFADDR
) == 0 && sa_in
->sin_addr
.s_addr
!= 0)
334 strlcpy(net_ip
, inet_ntoa(sa_in
->sin_addr
), sizeof net_ip
);
336 if (do_ifreq(&ifmr
, SIOCGIFNETMASK
) == 0 && sa_in
->sin_addr
.s_addr
!= 0)
337 strlcpy(net_mask
, inet_ntoa(sa_in
->sin_addr
), sizeof net_mask
);
339 if (do_ifreq(&ifmr
, SIOCGIFMEDIA
) == 0) {
340 /* Get the name of the media word */
341 modew
= ifmr
.ifm_current
;
342 strlcpy(net_media
, get_media_subtype_string(modew
),
344 /* and add any media options */
346 while ((media_opt
= get_media_option_string(&modew
)) != NULL
) {
347 strlcat(net_media
, sep
, sizeof net_media
);
348 strlcat(net_media
, media_opt
, sizeof net_media
);
355 #define get_if6interface_info()
358 get_if6interface_info(void)
363 textsize
= collect(T_OUTPUT
, &textbuf
,
364 "/sbin/ifconfig %s inet6 2>/dev/null", net_dev
);
368 (void)strtok(textbuf
, "\n"); /* ignore first line */
369 while ((t
= strtok(NULL
, "\n")) != NULL
) {
370 if (strncmp(t
, "\tinet6 ", 7) != 0)
373 if (strstr(t
, "tentative") || strstr(t
, "duplicated"))
375 if (strncmp(t
, "fe80:", 5) == 0)
379 while (*p
&& *p
!= ' ' && *p
!= '\n')
382 strlcpy(net_ip6
, t
, sizeof(net_ip6
));
393 char hostname
[MAXHOSTNAMELEN
+ 1];
396 /* Check host (and domain?) name */
397 if (gethostname(hostname
, sizeof(hostname
)) == 0 && hostname
[0] != 0) {
398 hostname
[sizeof(hostname
) - 1] = 0;
400 dot
= strchr(hostname
, '.');
402 /* if not found its just a host, punt on domain */
403 strlcpy(net_host
, hostname
, sizeof net_host
);
405 /* split hostname into host/domain parts */
407 strlcpy(net_host
, hostname
, sizeof net_host
);
408 strlcpy(net_domain
, dot
, sizeof net_domain
);
414 * recombine name parts split in get_host_info and config_network
415 * (common code moved here from write_etc_hosts)
418 recombine_host_domain(void)
420 static char recombined
[MAXHOSTNAMELEN
+ 1];
421 int l
= strlen(net_host
) - strlen(net_domain
);
423 strlcpy(recombined
, net_host
, sizeof(recombined
));
426 net_host
[l
- 1] != '.' ||
427 strcasecmp(net_domain
, net_host
+ l
) != 0) {
428 /* net_host isn't an FQDN. */
429 strlcat(recombined
, ".", sizeof(recombined
));
430 strlcat(recombined
, net_domain
, sizeof(recombined
));
441 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
449 * initialize as v6 client.
450 * we are sure that we will never become router with boot floppy :-)
451 * (include and use sysctl(8) if you are willing to)
454 init_v6kernel(int autoconf
)
457 int mib
[4] = {CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0};
459 mib
[3] = IPV6CTL_FORWARDING
;
461 (void)sysctl(mib
, 4, NULL
, NULL
, (void *)&v
, sizeof(v
));
463 mib
[3] = IPV6CTL_ACCEPT_RTADV
;
464 v
= autoconf
? 1 : 0;
465 (void)sysctl(mib
, 4, NULL
, NULL
, (void *)&v
, sizeof(v
));
471 size_t len
= sizeof(int);
473 int mib
[4] = {CTL_NET
, PF_INET6
, IPPROTO_IPV6
, IPV6CTL_DAD_COUNT
};
476 if (sysctl(mib
, 4, (void *)&v
, &len
, NULL
, 0) < 0) {
477 /* warn("sysctl(net.inet6.ip6.dadcount)"); */
478 return 1; /* guess */
485 handle_license(const char *dev
)
491 { "iwi", "/libdata/firmware/if_iwi/LICENSE.ipw2200-fw" },
492 { "ipw", "/libdata/firmware/if_ipw/LICENSE" },
497 for (i
= 0; i
< __arraycount(licdev
); i
++)
498 if (strncmp(dev
, licdev
[i
].dev
, 3) == 0) {
501 size_t len
= sizeof(int);
502 (void)snprintf(buf
, sizeof(buf
), "hw.%s.accept_eula",
504 if (sysctlbyname(buf
, &val
, &len
, NULL
, 0) != -1
507 msg_display(MSG_license
, dev
, licdev
[i
].lic
);
508 process_menu(MENU_yesno
, NULL
);
511 if (sysctlbyname(buf
, NULL
, NULL
, &val
,
514 add_sysctl_conf("%s=1", buf
);
523 * Get the information to configure the network, configure it and
524 * make sure both the gateway and the name server are up.
538 char **ap
, *slcmd
[10], *in_buf
;
539 char buffer
[STRSIZE
];
543 char dhcp_host
[STRSIZE
];
556 if (net_up
!= NULL
) {
557 /* XXX: some retry loops come here... */
558 /* active interfaces found */
559 msg_display(MSG_netup
, net_up
);
560 process_menu(MENU_yesno
, NULL
);
565 if (net_devices
== NULL
) {
566 /* No network interfaces found! */
567 msg_display(MSG_nonet
);
568 process_menu(MENU_ok
, NULL
);
574 tp
= strchr(net_devices
, ' ');
575 asprintf(&defname
, "%.*s", (int)(tp
- net_devices
), net_devices
);
576 for (prompt
= MSG_asknetdev
;; prompt
= MSG_badnet
) {
577 msg_prompt(prompt
, defname
, net_dev
, sizeof net_dev
- 1,
582 tp
= strstr(net_devices
, net_dev
);
585 if (tp
!= net_devices
&& tp
[-1] != ' ')
591 if (!handle_license(net_dev
))
594 slip
= net_dev
[0] == 's' && net_dev
[1] == 'l' &&
595 isdigit((unsigned char)net_dev
[2]);
597 /* If root is on NFS do not reconfigure the interface. */
598 if (statvfs("/", &sb
) == 0 && strcmp(sb
.f_fstypename
, "nfs") == 0) {
601 get_ifinterface_info();
602 get_if6interface_info();
607 /* Preload any defaults we can find */
608 get_ifinterface_info();
609 get_if6interface_info();
612 /* domain and host */
613 msg_display(MSG_netinfo
);
615 /* ethernet medium */
617 msg_prompt_add(MSG_net_media
, net_media
, net_media
,
621 * ifconfig does not allow media specifiers on
622 * IFM_MANUAL interfaces. Our UI gives no way
623 * to set an option back
624 * to null-string if it gets accidentally set.
625 * Check for plausible alternatives.
627 if (strcmp(net_media
, "<default>") == 0 ||
628 strcmp(net_media
, "default") == 0 ||
629 strcmp(net_media
, "<manual>") == 0 ||
630 strcmp(net_media
, "manual") == 0 ||
631 strcmp(net_media
, "<none>") == 0 ||
632 strcmp(net_media
, "none") == 0 ||
633 strcmp(net_media
, " ") == 0) {
637 if (*net_media
== '\0')
640 * We must set the media type here - to give dhcp
643 if (run_program(0, "/sbin/ifconfig %s media %s",
644 net_dev
, net_media
) == 0)
646 /* Failed to set - output the supported values */
647 if (collect(T_OUTPUT
, &textbuf
, "/sbin/ifconfig -m %s |"
648 "while IFS=; read line;"
649 " do [ \"$line\" = \"${line#*media}\" ] || "
651 " done", net_dev
) > 0)
652 msg_display(textbuf
);
657 /* try a dhcp configuration */
658 dhcp_config
= config_dhcp(net_dev
);
660 /* Get newly configured data off interface. */
661 get_ifinterface_info();
662 get_if6interface_info();
665 net_dhcpconf
|= DHCPCONF_IPADDR
;
668 * Extract default route from output of
671 if (collect(T_OUTPUT
, &textbuf
,
672 "/sbin/route -n show | "
673 "while read dest gateway flags;"
674 " do [ \"$dest\" = default ] && {"
675 " echo $gateway; break; };"
677 strlcpy(net_defroute
, textbuf
,
678 sizeof net_defroute
);
681 /* pull nameserver info out of /etc/resolv.conf */
682 if (collect(T_OUTPUT
, &textbuf
,
683 "cat /etc/resolv.conf 2>/dev/null |"
684 " while read keyword address rest;"
685 " do [ \"$keyword\" = nameserver "
686 " -a \"${address#*:}\" = "
687 "\"${address}\" ] && {"
688 " echo $address; break; };"
690 strlcpy(net_namesvr
, textbuf
,
693 if (net_namesvr
[0] != '\0')
694 net_dhcpconf
|= DHCPCONF_NAMESVR
;
696 /* pull domainname out of leases file */
697 get_dhcp_value(net_domain
, sizeof(net_domain
),
699 if (net_domain
[0] != '\0')
700 net_dhcpconf
|= DHCPCONF_DOMAIN
;
702 /* pull hostname out of leases file */
704 get_dhcp_value(dhcp_host
, sizeof(dhcp_host
),
706 if (dhcp_host
[0] != '\0') {
707 net_dhcpconf
|= DHCPCONF_HOST
;
708 strlcpy(net_host
, dhcp_host
, sizeof net_host
);
713 msg_prompt_add(MSG_net_domain
, net_domain
, net_domain
,
715 msg_prompt_add(MSG_net_host
, net_host
, net_host
, sizeof net_host
);
718 /* Manually configure IPv4 */
720 msg_prompt_add(MSG_net_ip
, net_ip
, net_ip
,
723 msg_prompt_add(MSG_net_srv_ip
, net_srv_ip
, net_srv_ip
,
725 else if (!nfs_root
) {
726 /* We don't want netmasks for SLIP */
727 octet0
= atoi(net_ip
);
729 if (0 <= octet0
&& octet0
<= 127)
730 strlcpy(net_mask
, "0xff000000",
732 else if (128 <= octet0
&& octet0
<= 191)
733 strlcpy(net_mask
, "0xffff0000",
735 else if (192 <= octet0
&& octet0
<= 223)
736 strlcpy(net_mask
, "0xffffff00",
739 msg_prompt_add(MSG_net_mask
, net_mask
, net_mask
,
742 msg_prompt_add(MSG_net_defroute
, net_defroute
, net_defroute
,
743 sizeof net_defroute
);
746 if (!dhcp_config
|| net_namesvr
[0] == 0)
747 msg_prompt_add(MSG_net_namesrv
, net_namesvr
, net_namesvr
,
751 /* IPv6 autoconfiguration */
755 process_menu(MENU_noyes
, deconst(MSG_Perform_IPv6_autoconfiguration
));
756 v6config
= yesno
? 1 : 0;
757 net_ip6conf
|= yesno
? IP6CONF_AUTOHOST
: 0;
761 process_menu(MENU_namesrv6
, NULL
);
763 msg_prompt_add(MSG_net_namesrv6
, net_namesvr6
,
764 net_namesvr6
, sizeof net_namesvr6
);
768 /* confirm the setting */
770 msg_display(MSG_netok_slip
, net_domain
, net_host
, net_dev
,
771 *net_ip
== '\0' ? "<none>" : net_ip
,
772 *net_srv_ip
== '\0' ? "<none>" : net_srv_ip
,
773 *net_mask
== '\0' ? "<none>" : net_mask
,
774 *net_namesvr
== '\0' ? "<none>" : net_namesvr
,
775 *net_defroute
== '\0' ? "<none>" : net_defroute
,
776 *net_media
== '\0' ? "<default>" : net_media
);
778 msg_display(MSG_netok
, net_domain
, net_host
, net_dev
,
779 *net_ip
== '\0' ? "<none>" : net_ip
,
780 *net_mask
== '\0' ? "<none>" : net_mask
,
781 *net_namesvr
== '\0' ? "<none>" : net_namesvr
,
782 *net_defroute
== '\0' ? "<none>" : net_defroute
,
783 *net_media
== '\0' ? "<default>" : net_media
);
785 msg_display_add(MSG_netokv6
,
786 !is_v6kernel() ? "<not supported>" :
787 (v6config
? "yes" : "no"),
788 *net_namesvr6
== '\0' ? "<none>" : net_namesvr6
);
791 process_menu(MENU_yesno
, deconst(MSG_netok_ok
));
793 msg_display(MSG_netagain
);
798 * we may want to perform checks against inconsistent configuration,
799 * like IPv4 DNS server without IPv4 configuration.
802 /* Create /etc/resolv.conf if a nameserver was given */
803 if (net_namesvr
[0] != '\0'
805 || net_namesvr6
[0] != '\0'
808 f
= fopen("/etc/resolv.conf", "w");
812 "%s", msg_string(MSG_resolv
));
813 (void)fprintf(stderr
, "%s", msg_string(MSG_resolv
));
816 scripting_fprintf(NULL
, "cat <<EOF >/etc/resolv.conf\n");
818 /* NB: ctime() returns a string ending in '\n' */
819 scripting_fprintf(f
, ";\n; BIND data file\n; %s %s;\n",
820 "Created by NetBSD sysinst on", ctime(&now
));
821 if (net_domain
[0] != '\0')
822 scripting_fprintf(f
, "search %s\n", net_domain
);
823 if (net_namesvr
[0] != '\0')
824 scripting_fprintf(f
, "nameserver %s\n", net_namesvr
);
826 if (net_namesvr6
[0] != '\0')
827 scripting_fprintf(f
, "nameserver %s\n", net_namesvr6
);
829 scripting_fprintf(NULL
, "EOF\n");
834 run_program(0, "/sbin/ifconfig lo0 127.0.0.1");
837 if (v6config
&& !nfs_root
) {
839 run_program(0, "/sbin/ifconfig %s up", net_dev
);
840 sleep(get_v6wait() + 1);
841 run_program(RUN_DISPLAY
, "/sbin/rtsol -D %s", net_dev
);
842 sleep(get_v6wait() + 1);
846 if (net_ip
[0] != '\0') {
848 /* XXX: needs 'ifconfig sl0 create' much earlier */
849 /* Set SLIP interface UP */
850 run_program(0, "/sbin/ifconfig %s inet %s %s up",
851 net_dev
, net_ip
, net_srv_ip
);
852 strcpy(sl_flags
, "-s 115200 -l /dev/tty00");
853 msg_prompt_win(MSG_slattach
, -1, 12, 70, 0,
854 sl_flags
, sl_flags
, 255);
856 /* XXX: wtf isn't run_program() used here? */
859 strcpy(buffer
, "/sbin/slattach ");
860 strcat(buffer
, sl_flags
);
863 for (ap
= slcmd
; (*ap
= strsep(&in_buf
, " ")) != NULL
;)
867 execvp(slcmd
[0], slcmd
);
869 wait4(pid
, &status
, WNOHANG
, 0);
870 } else if (!nfs_root
) {
871 if (net_mask
[0] != '\0') {
872 run_program(0, "/sbin/ifconfig %s inet %s netmask %s",
873 net_dev
, net_ip
, net_mask
);
875 run_program(0, "/sbin/ifconfig %s inet %s",
882 if (net_host
[0] != '\0')
883 sethostname(net_host
, strlen(net_host
));
885 /* Set a default route if one was given */
886 if (!nfs_root
&& net_defroute
[0] != '\0') {
887 run_program(RUN_DISPLAY
| RUN_PROGRESS
,
888 "/sbin/route -n flush -inet");
889 run_program(RUN_DISPLAY
| RUN_PROGRESS
,
890 "/sbin/route -n add default %s", net_defroute
);
894 * wait a couple of seconds for the interface to go live.
897 msg_display_add(MSG_wait_network
);
902 * ping should be verbose, so users can see the cause
903 * of a network failure.
907 if (v6config
&& network_up
) {
908 network_up
= !run_program(RUN_DISPLAY
| RUN_PROGRESS
,
909 "/sbin/ping6 -v -c 3 -n -I %s ff02::2", net_dev
);
911 if (net_namesvr6
[0] != '\0')
912 network_up
= !run_program(RUN_DISPLAY
| RUN_PROGRESS
,
913 "/sbin/ping6 -v -c 3 -n %s", net_namesvr6
);
917 if (net_namesvr
[0] != '\0' && network_up
)
918 network_up
= !run_program(RUN_DISPLAY
| RUN_PROGRESS
,
919 "/sbin/ping -v -c 5 -w 5 -o -n %s", net_namesvr
);
921 if (net_defroute
[0] != '\0' && network_up
)
922 network_up
= !run_program(RUN_DISPLAY
| RUN_PROGRESS
,
923 "/sbin/ping -v -c 5 -w 5 -o -n %s", net_defroute
);
930 ftp_fetch(const char *set_name
)
933 char ftp_user_encoded
[STRSIZE
];
934 char ftp_dir_encoded
[STRSIZE
];
939 * Invoke ftp to fetch the file.
941 * ftp.pass is quite likely to contain unsafe characters
942 * that need to be encoded in the URL (for example,
943 * "@", ":" and "/" need quoting). Let's be
944 * paranoid and also encode ftp.user and ftp.dir. (For
945 * example, ftp.dir could easily contain '~', which is
946 * unsafe by a strict reading of RFC 1738).
948 if (strcmp("ftp", ftp
.user
) == 0 && ftp
.pass
[0] == 0) {
951 ftp_user_encoded
[0] = 0;
954 cp
= url_encode(ftp_user_encoded
, ftp
.user
,
955 ftp_user_encoded
+ sizeof ftp_user_encoded
- 1,
956 RFC1738_SAFE_LESS_SHELL
, 0);
958 cp
= url_encode(cp
, ftp
.pass
,
959 ftp_user_encoded
+ sizeof ftp_user_encoded
- 1,
965 cp
= url_encode(ftp_dir_encoded
, ftp
.dir
,
966 ftp_dir_encoded
+ sizeof ftp_dir_encoded
- 1,
967 RFC1738_SAFE_LESS_SHELL_PLUS_SLASH
, 1);
968 if (cp
!= ftp_dir_encoded
&& cp
[-1] != '/')
972 while (*set_dir2
== '/')
975 url_encode(cp
, set_dir2
,
976 ftp_dir_encoded
+ sizeof ftp_dir_encoded
,
977 RFC1738_SAFE_LESS_SHELL_PLUS_SLASH
, 0);
979 rval
= run_program(RUN_DISPLAY
| RUN_PROGRESS
| RUN_XFER_DIR
,
980 "/usr/bin/ftp %s%s://%s%s/%s/%s%s",
981 ftp_opt
, ftp
.xfer_type
, ftp_user_encoded
, ftp
.host
,
982 ftp_dir_encoded
, set_name
, dist_postfix
);
984 return rval
? SET_RETRY
: SET_OK
;
988 do_config_network(void)
992 while ((ret
= config_network()) <= 0) {
995 msg_display(MSG_netnotup
);
996 process_menu(MENU_yesno
, NULL
);
998 msg_display(MSG_netnotup_continueanyway
);
999 process_menu(MENU_yesno
, NULL
);
1010 get_via_ftp(const char *xfer_type
)
1013 if (do_config_network() != 0)
1016 process_menu(MENU_ftpsource
, deconst(xfer_type
));
1018 /* We'll fetch each file just before installing it */
1019 fetch_fn
= ftp_fetch
;
1020 ftp
.xfer_type
= xfer_type
;
1021 snprintf(ext_dir
, sizeof ext_dir
, "%s/%s", target_prefix(),
1022 xfer_dir
+ (*xfer_dir
== '/'));
1032 if (do_config_network() != 0)
1035 /* If root is on NFS and we have sets, skip this step. */
1036 if (statvfs(set_dir
, &sb
) == 0 &&
1037 strcmp(sb
.f_fstypename
, "nfs") == 0) {
1038 strlcpy(ext_dir
, set_dir
, sizeof ext_dir
);
1042 /* Get server and filepath */
1043 process_menu(MENU_nfssource
, NULL
);
1046 if (run_program(0, "/sbin/mount -r -o -2,-i,-r=1024 -t nfs %s:%s /mnt2",
1052 snprintf(ext_dir
, sizeof ext_dir
, "/mnt2/%s", set_dir
);
1054 /* return location, don't clean... */
1059 * write the new contents of /etc/hosts to the specified file
1062 write_etc_hosts(FILE *f
)
1064 scripting_fprintf(f
, "#\n");
1065 scripting_fprintf(f
, "# Added by NetBSD sysinst\n");
1066 scripting_fprintf(f
, "#\n");
1068 if (net_domain
[0] != '\0')
1069 scripting_fprintf(f
, "127.0.0.1 localhost.%s\n", net_domain
);
1071 scripting_fprintf(f
, "%s\t", net_ip
);
1072 if (net_domain
[0] != '\0')
1073 scripting_fprintf(f
, "%s ", recombine_host_domain());
1074 scripting_fprintf(f
, "%s\n", net_host
);
1078 * Write the network config info the user entered via menus into the
1079 * config files in the target disk. Be careful not to lose any
1080 * information we don't immediately add back, in case the install
1081 * target is the currently-active root.
1084 mnt_net_config(void)
1086 char ifconfig_fn
[STRSIZE
];
1087 FILE *ifconf
= NULL
;
1091 process_menu(MENU_yesno
, deconst(MSG_mntnetconfig
));
1095 /* Write hostname to /etc/rc.conf */
1096 if ((net_dhcpconf
& DHCPCONF_HOST
) == 0)
1097 add_rc_conf("hostname=%s\n", recombine_host_domain());
1099 /* If not running in target, copy resolv.conf there. */
1100 if ((net_dhcpconf
& DHCPCONF_NAMESVR
) == 0) {
1102 if (net_namesvr
[0] != '\0')
1103 dup_file_into_target("/etc/resolv.conf");
1106 * not sure if it is a good idea, to allow dhcp config to
1107 * override IPv6 configuration
1109 if (net_namesvr
[0] != '\0' || net_namesvr6
[0] != '\0')
1110 dup_file_into_target("/etc/resolv.conf");
1115 * bring the interface up, it will be necessary for IPv6, and
1116 * it won't make trouble with IPv4 case either
1118 snprintf(ifconfig_fn
, sizeof ifconfig_fn
, "/etc/ifconfig.%s", net_dev
);
1119 ifconf
= target_fopen(ifconfig_fn
, "w");
1120 if (ifconf
!= NULL
) {
1121 scripting_fprintf(NULL
, "cat <<EOF >>%s%s\n",
1122 target_prefix(), ifconfig_fn
);
1123 scripting_fprintf(ifconf
, "up\n");
1124 if (*net_media
!= '\0')
1125 scripting_fprintf(ifconf
, "media %s\n", net_media
);
1126 scripting_fprintf(NULL
, "EOF\n");
1129 if ((net_dhcpconf
& DHCPCONF_IPADDR
) == 0) {
1132 /* Write IPaddr and netmask to /etc/ifconfig.if[0-9] */
1133 if (ifconf
!= NULL
) {
1134 scripting_fprintf(NULL
, "cat <<EOF >>%s%s\n",
1135 target_prefix(), ifconfig_fn
);
1136 if (*net_media
!= '\0')
1137 scripting_fprintf(ifconf
,
1138 "%s netmask %s media %s\n",
1139 net_ip
, net_mask
, net_media
);
1141 scripting_fprintf(ifconf
, "%s netmask %s\n",
1143 scripting_fprintf(NULL
, "EOF\n");
1147 * Add IPaddr/hostname to /etc/hosts.
1148 * Be careful not to clobber any existing contents.
1149 * Relies on ordered search of /etc/hosts. XXX YP?
1151 hosts
= target_fopen("/etc/hosts", "a");
1153 scripting_fprintf(NULL
, "cat <<EOF >>%s/etc/hosts\n",
1155 write_etc_hosts(hosts
);
1156 (void)fclose(hosts
);
1157 scripting_fprintf(NULL
, "EOF\n");
1162 add_rc_conf("defaultroute=\"%s\"\n", net_defroute
);
1164 add_rc_conf("ifconfig_%s=dhcp\n", net_dev
);
1168 if ((net_ip6conf
& IP6CONF_AUTOHOST
) != 0) {
1169 add_rc_conf("ip6mode=autohost\n");
1170 if (ifconf
!= NULL
) {
1171 scripting_fprintf(NULL
, "cat <<EOF >>%s%s\n",
1172 target_prefix(), ifconfig_fn
);
1173 scripting_fprintf(ifconf
, "!rtsol $int\n");
1174 scripting_fprintf(NULL
, "EOF\n");
1186 config_dhcp(char *inter
)
1191 * Don't bother checking for an existing instance of dhcpcd, just
1192 * ask it to renew the lease. It will fork and daemonize if there
1193 * wasn't already an instance.
1196 if (!file_mode_match(DHCPCD
, S_IFREG
))
1198 process_menu(MENU_yesno
, deconst(MSG_Perform_DHCP_autoconfiguration
));
1200 /* spawn off dhcpcd and wait for parent to exit */
1201 dhcpautoconf
= run_program(RUN_DISPLAY
| RUN_PROGRESS
,
1202 "%s -d -n %s", DHCPCD
, inter
);
1203 return dhcpautoconf
? 0 : 1;
1209 get_dhcp_value(char *targ
, size_t l
, const char *var
)
1211 static const char *lease_data
= "/tmp/dhcpcd-lease";
1214 size_t len
, var_len
;
1216 if ((fp
= fopen(lease_data
, "r")) == NULL
) {
1217 warn("Could not open %s", lease_data
);
1222 var_len
= strlen(var
);
1224 while ((line
= fgetln(fp
, &len
)) != NULL
) {
1225 if (line
[len
- 1] == '\n')
1229 if (memcmp(line
, var
, var_len
))
1231 if (line
[var_len
] != '=')
1233 line
+= var_len
+ 1;
1235 strlcpy(targ
, line
, l
> len
? len
+ 1: l
);