2 * Copyright (c) 2017 Denys Vlasenko <vda.linux@googlemail.com>
4 * Licensed under GPLv2, see file LICENSE in this source tree.
6 //config:config IPCONFIG
7 //config: bool "ipconfig"
10 //config: (Auto)configure network.
12 //applet:IF_IPCONFIG(APPLET(ipconfig, BB_DIR_BIN, BB_SUID_DROP))
14 //kbuild:lib-$(CONFIG_IPCONFIG) += ipconfig.o
23 #define G (*ptr_to_globals)
24 #define INIT_G() do { \
25 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
38 parse_method(const char *method)
42 fixed = (method[0] != '\0');
45 fixed = index_in_strings(
64 parse_addr(const char *ip)
67 if (inet_aton(ip, &in) == 0)
68 bb_error_msg_and_die("bad IP address '%s'", ip);
73 find_device(llist_t *iface_list, const char *name)
76 struct dev *dev = (void*) iface_list->data;
77 if (strcmp(dev->name, name) == 0)
79 iface_list = iface_list->link;
85 set_from_template(struct dev *dev, struct dev *template)
87 if (template->ip_addr != 0)
88 dev->ip_addr = template->ip_addr;
89 if (template->ip_netmask != 0)
90 dev->ip_netmask = template->ip_netmask;
91 if (template->ip_server != 0)
92 dev->ip_server = template->ip_server;
93 if (template->ip_router != 0)
94 dev->ip_router = template->ip_router;
95 dev->fixed = template->fixed;
98 // "ip=PROTO" - also implies -o
99 // "nfsaddrs=PROTO" - also implies -o
101 // "[ip=/nfsaddrs=]IP:SERVER_IP:ROUTER:NETMASK:HOSTNAME:IFACE:METHOD"
102 // all optional. trailing empty :: can be skipped, only one : needs to be there
103 // (to distinguish from other formats).
104 // ":::::eth0" - dhcp on eth0
105 // ":" - dhcp on all ifaces
106 // "::1.2.3.4" - dhcp on all ifaces, gateway is 1.2.3.4 (fairly nonsensical)
108 add_all_devices(llist_t **iface_list, struct dev *template);
110 add_device(llist_t **iface_list, char *ip)
114 dev = xzalloc(sizeof(*dev));
115 dev->fixed = G.fixed;
117 if (strncmp("ip=", ip, 3) == 0
118 || strncmp("nfsaddrs=", ip, 9) == 0
122 ip = strchr(ip, '=') + 1;
123 fixed = parse_method(ip);
125 add_all_devices(iface_list, dev);
131 if (!strchr(ip, ':')) {
136 char *next = strchr(ip, ':');
140 bb_error_msg_and_die("too many options for %s", dev->name);
141 if (ip[0]) switch (opt) {
143 dev->ip_addr = parse_addr(ip);
146 dev->ip_server = parse_addr(ip);
149 dev->ip_router = parse_addr(ip);
152 dev->ip_netmask = parse_addr(ip);
155 if (G.hostname && strcmp(G.hostname, ip) != 0)
156 bb_error_msg_and_die("hostname must be the same");
163 dev->fixed = parse_method(ip);
171 if (dev->name == NULL
172 || strcmp(dev->name, "all") == 0
174 add_all_devices(iface_list, dev);
178 llist_add_to_end(iface_list, dev);
183 add_all_devices(llist_t **iface_list, struct dev *template)
187 #define sys_class_net "/sys/class/net"
189 /* All forms of "config all ifaces" imply -o */
192 d = opendir(sys_class_net);
196 while ((de = readdir(d)) != NULL) {
199 char p[sizeof(long)*3];
203 /* Exclude devices beginning with dots as well as . and .. */
204 if (de->d_name[0] == '.')
206 filename = xasprintf("%s/%s/flags", sys_class_net, de->d_name);
207 r = open_read_close(filename, p, sizeof(p) - 1);
212 /* file's format is "0xNNNN\n" */
213 flags = bb_strtoul(p, NULL, 0);
215 * Heuristic for if this is a reasonable boot interface.
216 * This is the same logic the in-kernel ipconfig uses.
218 if (flags & IFF_LOOPBACK)
220 if (!(flags & (IFF_BROADCAST | IFF_POINTOPOINT)))
222 if (find_device(*iface_list, de->d_name))
224 dev = add_device(iface_list, xstrdup(de->d_name));
226 set_from_template(dev, template);
232 //usage:#define ipconfig_trivial_usage
233 //usage: "[-c METHOD] [-t TIMEOUT] [-on] [-i VENDOR_ID] [-p PORT] [-d] IFACE..."
234 //usage:#define ipconfig_full_usage "\n\n"
235 //usage: "(Auto)configure network"
237 //usage: "\n"" -c METHOD off/none/static or on/dhcp (default)"
238 //usage: "\n"" -t SECONDS Give up after SECONDS"
239 //usage: "\n"" -o Stop after one interface is configured"
240 //usage: "\n"" -n Dry run"
241 //usage: "\n"" -i VENDOR_ID DHCP vendor id (default '')"
242 //usage: "\n"" -p PORT DHCP port to use"
243 //usage: "\n"" [-d] IFACE... Interface(s)"
245 //usage: "\n"" IFACE can be:"
246 //usage: "\n"" all - configure all interfaces"
247 //usage: "\n"" IFACE - configure this interface"
248 //usage: "\n"" IP:SERVER_IP:ROUTER:NETMASK:HOSTNAME:IFACE:METHOD (all optional)"
249 // TIMEOUT defaults to infinite
250 // -d actually is an option with an argument
251 // (not a clue why klibc-utils has two ways to specify interfaces)
252 int ipconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
253 int ipconfig_main(int argc UNUSED_PARAM, char **argv)
255 const char *method = "";
256 const char *vendor_id = "";
257 llist_t *devname_list = NULL;
267 &method, &timeout, &vendor_id, &port, &devname_list
271 G.fixed = parse_method(method);
277 add_device(&iface_list, (char*) llist_pop(&devname_list));
279 add_device(&iface_list, *argv++);
282 struct dev *dev = (void*) iface_list->data;
283 printf("name:'%s'\n", dev->name);
284 printf("fixed:%u\n" , dev->fixed);
285 printf("ip:%s/" , inet_ntoa(*(struct in_addr*)&dev->ip_addr));
286 printf("%s\n" , inet_ntoa(*(struct in_addr*)&dev->ip_netmask));
287 printf("server:%s\n", inet_ntoa(*(struct in_addr*)&dev->ip_server));
288 printf("router:%s\n", inet_ntoa(*(struct in_addr*)&dev->ip_router));
289 iface_list = iface_list->link;
291 bb_error_msg("hostname:'%s'", G.hostname);
292 bb_error_msg("fixed:%u", G.fixed);
296 //After device is configured, write out a "/run/net-IFACE.conf" file:
297 // // udchcp env values:
298 //write_option("DEVICE", dev->name); interface=eth0
299 //write_option("PROTO", method);
300 //write_option("IPV4ADDR", dev->ip_addr); ip=10.43.17.38
301 //write_option("IPV4BROADCAST", dev->ip_broadcast); subnet=255.255.255.0 mask=24
302 //write_option("IPV4NETMASK", dev->ip_netmask); subnet=255.255.255.0 mask=24
303 //write_option("IPV4GATEWAY", dev->ip_gateway); router=10.43.17.254
304 //write_option("IPV4DNS0", dev->ip_nameserver[0]); dns=10.38.5.26 10.11.5.19
305 //write_option("IPV4DNS1", dev->ip_nameserver[1]); dns=10.38.5.26 10.11.5.19
306 //write_option("HOSTNAME", dev->hostname); hostname="STR"
307 //write_option("DNSDOMAIN", dev->dnsdomainname); domain=domain.com
308 //write_option("NISDOMAIN", dev->nisdomainname); nisdomain="STR"
309 //write_option("ROOTSERVER", my_inet_ntoa(dev->ip_server)); serverid=10.44.6.2
310 //write_option("ROOTPATH", dev->bootpath); rootpath="STR"
311 //write_option("filename", dev->filename); boot_file=/pxelinux.0
312 //write_option("UPTIME", dev->uptime); sysinfo()->uptime
313 //write_option("DHCPLEASETIME", dev->dhcpleasetime); lease=44148
314 //write_option("DOMAINSEARCH", dev->domainsearch); search="ABC DEF"
316 //(write_option writes out single-quote escaped string, VAR='VAL')