aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rwxr-xr-xexamples/udhcp/sample.bound (renamed from examples/udhcpc/default.bound)2
-rwxr-xr-xexamples/udhcp/sample.deconfig (renamed from examples/udhcpc/default.deconfig)0
-rwxr-xr-xexamples/udhcp/sample.nak4
-rwxr-xr-xexamples/udhcp/sample.renew (renamed from examples/udhcpc/default.renew)4
-rw-r--r--examples/udhcp/sample.script (renamed from examples/udhcpc/default.script)2
-rw-r--r--examples/udhcp/simple.script39
-rw-r--r--examples/udhcp/udhcpd.conf116
-rw-r--r--include/applets.h8
-rw-r--r--include/usage.h20
-rw-r--r--networking/Makefile.in1
-rw-r--r--networking/config.in3
-rw-r--r--networking/udhcp/AUTHORS13
-rw-r--r--networking/udhcp/COPYING339
-rw-r--r--networking/udhcp/ChangeLog246
-rw-r--r--networking/udhcp/Makefile.in46
-rw-r--r--networking/udhcp/README197
-rw-r--r--networking/udhcp/TODO17
-rw-r--r--networking/udhcp/arpping.c105
-rw-r--r--networking/udhcp/arpping.h30
-rw-r--r--networking/udhcp/clientpacket.c239
-rw-r--r--networking/udhcp/clientpacket.h12
-rw-r--r--networking/udhcp/config.in18
-rw-r--r--networking/udhcp/debug.h41
-rw-r--r--networking/udhcp/dhcpc.c559
-rw-r--r--networking/udhcp/dhcpc.h34
-rw-r--r--networking/udhcp/dhcpd.c287
-rw-r--r--networking/udhcp/dhcpd.h131
-rw-r--r--networking/udhcp/dumpleases.c112
-rw-r--r--networking/udhcp/files.c284
-rw-r--r--networking/udhcp/files.h17
-rw-r--r--networking/udhcp/frontend.c16
-rw-r--r--networking/udhcp/leases.c151
-rw-r--r--networking/udhcp/leases.h24
-rw-r--r--networking/udhcp/libbb_udhcp.h29
-rw-r--r--networking/udhcp/options.c230
-rw-r--r--networking/udhcp/options.h40
-rw-r--r--networking/udhcp/packet.c203
-rw-r--r--networking/udhcp/packet.h41
-rw-r--r--networking/udhcp/pidfile.c69
-rw-r--r--networking/udhcp/pidfile.h26
-rw-r--r--networking/udhcp/script.c228
-rw-r--r--networking/udhcp/script.h6
-rw-r--r--networking/udhcp/serverpacket.c263
-rw-r--r--networking/udhcp/serverpacket.h11
-rw-r--r--networking/udhcp/socket.c157
-rw-r--r--networking/udhcp/socket.h9
-rw-r--r--networking/udhcpc.c1587
48 files changed, 4421 insertions, 1597 deletions
diff --git a/Makefile b/Makefile
index 43c2a48b5..693d47b7c 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ include $(TOPDIR).config
22include $(TOPDIR)Rules.mak 22include $(TOPDIR)Rules.mak
23SUBDIRS:=applets archival archival/libunarchive console-tools \ 23SUBDIRS:=applets archival archival/libunarchive console-tools \
24 editors fileutils findutils init miscutils modutils networking \ 24 editors fileutils findutils init miscutils modutils networking \
25 procps loginutils shell shellutils sysklogd \ 25 networking/udhcp procps loginutils shell shellutils sysklogd \
26 textutils util-linux libbb libpwdgrp 26 textutils util-linux libbb libpwdgrp
27 27
28all: do-it-all 28all: do-it-all
diff --git a/examples/udhcpc/default.bound b/examples/udhcp/sample.bound
index 98f3aa97e..200352672 100755
--- a/examples/udhcpc/default.bound
+++ b/examples/udhcp/sample.bound
@@ -1,7 +1,7 @@
1#!/bin/sh 1#!/bin/sh
2# Sample udhcpc renew script 2# Sample udhcpc renew script
3 3
4RESOLV_CONF="/etc/resolv.conf" 4RESOLV_CONF="/etc/udhcpc/resolv.conf"
5 5
6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" 6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
7[ -n "$subnet" ] && NETMASK="netmask $subnet" 7[ -n "$subnet" ] && NETMASK="netmask $subnet"
diff --git a/examples/udhcpc/default.deconfig b/examples/udhcp/sample.deconfig
index b221bcf12..b221bcf12 100755
--- a/examples/udhcpc/default.deconfig
+++ b/examples/udhcp/sample.deconfig
diff --git a/examples/udhcp/sample.nak b/examples/udhcp/sample.nak
new file mode 100755
index 000000000..f4d08e669
--- /dev/null
+++ b/examples/udhcp/sample.nak
@@ -0,0 +1,4 @@
1#!/bin/sh
2# Sample udhcpc nak script
3
4echo Received a NAK: $message
diff --git a/examples/udhcpc/default.renew b/examples/udhcp/sample.renew
index b64c1fe72..c953e9758 100755
--- a/examples/udhcpc/default.renew
+++ b/examples/udhcp/sample.renew
@@ -1,7 +1,7 @@
1#!/bin/sh 1#!/bin/sh
2# Sample udhcpc bound script 2# Sample udhcpc bound script
3 3
4RESOLV_CONF="/etc/resolv.conf" 4RESOLV_CONF="/etc/udhcpc/resolv.conf"
5 5
6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" 6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
7[ -n "$subnet" ] && NETMASK="netmask $subnet" 7[ -n "$subnet" ] && NETMASK="netmask $subnet"
@@ -27,4 +27,4 @@ for i in $dns
27do 27do
28 echo adding dns $i 28 echo adding dns $i
29 echo nameserver $i >> $RESOLV_CONF 29 echo nameserver $i >> $RESOLV_CONF
30done 30done \ No newline at end of file
diff --git a/examples/udhcpc/default.script b/examples/udhcp/sample.script
index f5920ba96..9b717ac3c 100644
--- a/examples/udhcpc/default.script
+++ b/examples/udhcp/sample.script
@@ -4,4 +4,4 @@
4# common initialization first, especially if more dhcp event notifications 4# common initialization first, especially if more dhcp event notifications
5# are added. 5# are added.
6 6
7exec /usr/share/udhcpc/default.$1 7exec /usr/share/udhcpc/sample.$1
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script
new file mode 100644
index 000000000..a52a7f812
--- /dev/null
+++ b/examples/udhcp/simple.script
@@ -0,0 +1,39 @@
1#!/bin/sh
2
3# udhcpc script edited by Tim Riker <Tim@Rikers.org>
4
5[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
6
7RESOLV_CONF="/etc/resolv.conf"
8[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
9[ -n "$subnet" ] && NETMASK="netmask $subnet"
10
11case "$1" in
12 deconfig)
13 /sbin/ifconfig $interface 0.0.0.0
14 ;;
15
16 renew|bound)
17 /sbin/ifconfig $interface $ip $BROADCAST $NETMASK
18
19 if [ -n "$router" ] ; then
20 echo "deleting routers"
21 while route del default gw 0.0.0.0 dev $interface ; do
22 :
23 done
24
25 for i in $router ; do
26 route add default gw $i dev $interface
27 done
28 fi
29
30 echo -n > $RESOLV_CONF
31 [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
32 for i in $dns ; do
33 echo adding dns $i
34 echo nameserver $i >> $RESOLV_CONF
35 done
36 ;;
37esac
38
39exit 0
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf
new file mode 100644
index 000000000..36cb58c3f
--- /dev/null
+++ b/examples/udhcp/udhcpd.conf
@@ -0,0 +1,116 @@
1# Sample udhcpd configuration file (/etc/udhcpd.conf)
2
3# The start and end of the IP lease block
4
5start 192.168.0.20 #default: 192.168.0.20
6end 192.168.0.254 #default: 192.168.0.254
7
8
9# The interface that udhcpd will use
10
11interface eth0 #default: eth0
12
13
14# The maximim number of leases (includes addressesd reserved
15# by OFFER's, DECLINE's, and ARP conficts
16
17#max_leases 254 #default: 254
18
19
20# If remaining is true (default), udhcpd will store the time
21# remaining for each lease in the udhcpd leases file. This is
22# for embedded systems that cannot keep time between reboots.
23# If you set remaining to no, the absolute time that the lease
24# expires at will be stored in the dhcpd.leases file.
25
26#remaining yes #default: yes
27
28
29# The time period at which udhcpd will write out a dhcpd.leases
30# file. If this is 0, udhcpd will never automatically write a
31# lease file. (specified in seconds)
32
33#auto_time 7200 #default: 7200 (2 hours)
34
35
36# The amount of time that an IP will be reserved (leased) for if a
37# DHCP decline message is received (seconds).
38
39#decline_time 3600 #default: 3600 (1 hour)
40
41
42# The amount of time that an IP will be reserved (leased) for if an
43# ARP conflct occurs. (seconds
44
45#conflict_time 3600 #default: 3600 (1 hour)
46
47
48# How long an offered address is reserved (leased) in seconds
49
50#offer_time 60 #default: 60 (1 minute)
51
52# If a lease to be given is below this value, the full lease time is
53# instead used (seconds).
54
55#min_lease 60 #defult: 60
56
57
58# The location of the leases file
59
60#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
61
62# The location of the pid file
63#pidfile /var/run/udhcpd.pid #default: /var/run/udhcpd.pid
64
65# Everytime udhcpd writes a leases file, the below script will be called.
66# Useful for writing the lease file to flash every few hours.
67
68#notify_file #default: (no script)
69
70#notify_file dumpleases # <--- usefull for debugging
71
72# The following are bootp specific options, setable by udhcpd.
73
74#siaddr 192.168.0.22 #default: 0.0.0.0
75
76#sname zorak #default: (none)
77
78#boot_file /var/nfs_root #default: (none)
79
80# The remainer of options are DHCP options and can be specifed with the
81# keyword 'opt' or 'option'. If an option can take multiple items, such
82# as the dns option, they can be listed on the same line, or multiple
83# lines. The only option with a default is 'lease'.
84
85#Examles
86opt dns 192.168.10.2 192.168.10.10
87option subnet 255.255.255.0
88opt router 192.168.10.2
89opt wins 192.168.10.10
90option dns 129.219.13.81 # appened to above DNS servers for a total of 3
91option domain local
92option lease 864000 # 10 days of seconds
93
94
95# Currently supported options, for more info, see options.c
96#subnet
97#timezone
98#router
99#timesvr
100#namesvr
101#dns
102#logsvr
103#cookiesvr
104#lprsvr
105#bootsize
106#domain
107#swapsvr
108#rootpath
109#ipttl
110#mtu
111#broadcast
112#wins
113#lease
114#ntpsrv
115#tftp
116#bootfile \ No newline at end of file
diff --git a/include/applets.h b/include/applets.h
index 60928aef2..e59342051 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -152,6 +152,9 @@
152#ifdef CONFIG_DUMPKMAP 152#ifdef CONFIG_DUMPKMAP
153 APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN, _BB_SUID_NEVER) 153 APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN, _BB_SUID_NEVER)
154#endif 154#endif
155#ifdef CONFIG_DUMPLEASES
156 APPLET(dumpleases, dumpleases_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
157#endif
155#ifdef CONFIG_DUTMP 158#ifdef CONFIG_DUTMP
156 APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER) 159 APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
157#endif 160#endif
@@ -495,7 +498,10 @@
495 APPLET(tty, tty_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) 498 APPLET(tty, tty_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
496#endif 499#endif
497#ifdef CONFIG_UDHCPC 500#ifdef CONFIG_UDHCPC
498 APPLET(udhcpc, udhcpc_main, _BB_DIR_SBIN, _BB_SUID_NEVER) 501 APPLET(udhcpc, udhcpc_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
502#endif
503#ifdef CONFIG_UDHCPD
504 APPLET(udhcpd, udhcpd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
499#endif 505#endif
500#ifdef CONFIG_UMOUNT 506#ifdef CONFIG_UMOUNT
501 APPLET(umount, umount_main, _BB_DIR_BIN, _BB_SUID_NEVER) 507 APPLET(umount, umount_main, _BB_DIR_BIN, _BB_SUID_NEVER)
diff --git a/include/usage.h b/include/usage.h
index 8dd501dde..324341524 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -385,6 +385,14 @@
385#define dumpkmap_example_usage \ 385#define dumpkmap_example_usage \
386 "$ dumpkmap > keymap\n" 386 "$ dumpkmap > keymap\n"
387 387
388#define dumpleases_trivial_usage \
389 "[-r|-a] [-f LEASEFILE]"
390#define dumpleases_full_usage \
391 "Usage: dumpleases -f <file> -[r|a]\n" \
392 "\t-f,\t--file=FILENAME\tLeases file to load\n" \
393 "\t-r,\t--remaining\tInterepret lease times as time remaing\n" \
394 "\t-a,\t--absolute\tInterepret lease times as expire time\n"
395
388#define dutmp_trivial_usage \ 396#define dutmp_trivial_usage \
389 "[FILE]" 397 "[FILE]"
390#define dutmp_full_usage \ 398#define dutmp_full_usage \
@@ -1945,12 +1953,14 @@
1945 "/dev/tty2\n" 1953 "/dev/tty2\n"
1946 1954
1947#define udhcpc_trivial_usage \ 1955#define udhcpc_trivial_usage \
1948 "[-fqv] [-c CLIENTID] [-H HOSTNAME] [-i INTERFACE]\n[-p file] [-r IP] [-s script]" 1956 "[-fbnqv] [-c CLIENTID] [-H HOSTNAME] [-i INTERFACE]\n[-p pidfile] [-r IP] [-s script]"
1949#define udhcpc_full_usage \ 1957#define udhcpc_full_usage \
1950 "\tUsage: udhcpcd [OPTIONS]\n" \ 1958 "\tUsage: udhcpc [OPTIONS]\n" \
1951 "\t-c,\t--clientid=CLIENTID\tClient identifier\n" \ 1959 "\t-c,\t--clientid=CLIENTID\tClient identifier\n" \
1952 "\t-H,\t--hostname=HOSTNAME\tClient hostname\n" \ 1960 "\t-H,\t--hostname=HOSTNAME\tClient hostname\n" \
1961 "\t-h,\t \tAlias for -h\n" \
1953 "\t-f,\t--foreground\tDo not fork after getting lease\n" \ 1962 "\t-f,\t--foreground\tDo not fork after getting lease\n" \
1963 "\t-b,\t--background\tFork to background if lease cannot be immediately negotiated.\n" \
1954 "\t-i,\t--interface=INTERFACE\tInterface to use (default: eth0)\n" \ 1964 "\t-i,\t--interface=INTERFACE\tInterface to use (default: eth0)\n" \
1955 "\t-n,\t--now\tExit with failure if lease cannot be immediately negotiated.\n" \ 1965 "\t-n,\t--now\tExit with failure if lease cannot be immediately negotiated.\n" \
1956 "\t-p,\t--pidfile=file\tStore process ID of daemon in file\n" \ 1966 "\t-p,\t--pidfile=file\tStore process ID of daemon in file\n" \
@@ -1959,6 +1969,12 @@
1959 "\t-s,\t--script=file\tRun file at dhcp events (default: /usr/share/udhcpc/default.script)\n" \ 1969 "\t-s,\t--script=file\tRun file at dhcp events (default: /usr/share/udhcpc/default.script)\n" \
1960 "\t-v,\t--version\tDisplay version" 1970 "\t-v,\t--version\tDisplay version"
1961 1971
1972#define udhcpd_trivial_usage \
1973 "[configfile]\n" \
1974
1975#define udhcpd_full_usage \
1976 "\tUsage: udhcpd [configfile]\n"
1977
1962#ifdef CONFIG_FEATURE_MOUNT_FORCE 1978#ifdef CONFIG_FEATURE_MOUNT_FORCE
1963 #define USAGE_MOUNT_FORCE(a) a 1979 #define USAGE_MOUNT_FORCE(a) a
1964#else 1980#else
diff --git a/networking/Makefile.in b/networking/Makefile.in
index 510c8119d..d6c8592d2 100644
--- a/networking/Makefile.in
+++ b/networking/Makefile.in
@@ -35,7 +35,6 @@ NETWORKING-$(CONFIG_TELNET) += telnet.o
35NETWORKING-$(CONFIG_TELNETD) += telnetd.o 35NETWORKING-$(CONFIG_TELNETD) += telnetd.o
36NETWORKING-$(CONFIG_TFTP) += tftp.o 36NETWORKING-$(CONFIG_TFTP) += tftp.o
37NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o 37NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o
38NETWORKING-$(CONFIG_UDHCPC) += udhcpc.o
39NETWORKING-$(CONFIG_WGET) += wget.o 38NETWORKING-$(CONFIG_WGET) += wget.o
40 39
41libraries-y+=$(NETWORKING_DIR)$(NETWORKING_AR) 40libraries-y+=$(NETWORKING_DIR)$(NETWORKING_AR)
diff --git a/networking/config.in b/networking/config.in
index 4438a8c6c..bc14940d5 100644
--- a/networking/config.in
+++ b/networking/config.in
@@ -47,12 +47,13 @@ if [ "$CONFIG_TRACEROUTE" = "y" ]; then
47 bool ' Enable verbose output' CONFIG_FEATURE_TRACEROUTE_VERBOSE 47 bool ' Enable verbose output' CONFIG_FEATURE_TRACEROUTE_VERBOSE
48 bool ' Enable SO_DEBUG option' CONFIG_FEATURE_TRACEROUTE_SO_DEBUG 48 bool ' Enable SO_DEBUG option' CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
49fi 49fi
50bool 'udhcpc' CONFIG_UDHCPC
51bool 'wget' CONFIG_WGET 50bool 'wget' CONFIG_WGET
52if [ "$CONFIG_WGET" = "y" ]; then 51if [ "$CONFIG_WGET" = "y" ]; then
53 bool ' Enable a nifty process meter (+2k)' CONFIG_FEATURE_WGET_STATUSBAR 52 bool ' Enable a nifty process meter (+2k)' CONFIG_FEATURE_WGET_STATUSBAR
54 bool ' Enable HTTP authentication' CONFIG_FEATURE_WGET_AUTHENTICATION 53 bool ' Enable HTTP authentication' CONFIG_FEATURE_WGET_AUTHENTICATION
55fi 54fi
56 55
56source networking/udhcp/config.in
57
57endmenu 58endmenu
58 59
diff --git a/networking/udhcp/AUTHORS b/networking/udhcp/AUTHORS
new file mode 100644
index 000000000..89a6de41d
--- /dev/null
+++ b/networking/udhcp/AUTHORS
@@ -0,0 +1,13 @@
1udhcp server/client package
2-----------------------
3
4Russ Dill <Russ.Dill@asu.edu>
5Matthew Ramsay <matthewr@moreton.com.au>
6Chris Trew <christ@moreton.com.au>
7
8Other Credits:
9--------------
10Moreton Bay (http://www.moretonbay.com/)
11Lineo (http://opensource.lineo.com)
12
13
diff --git a/networking/udhcp/COPYING b/networking/udhcp/COPYING
new file mode 100644
index 000000000..a43ea2126
--- /dev/null
+++ b/networking/udhcp/COPYING
@@ -0,0 +1,339 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 675 Mass Ave, Cambridge, MA 02139, USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Library General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 Appendix: How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) 19yy <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License
307 along with this program; if not, write to the Free Software
308 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
309
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) 19yy name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Library General
339Public License instead of this License.
diff --git a/networking/udhcp/ChangeLog b/networking/udhcp/ChangeLog
new file mode 100644
index 000000000..9c269d85d
--- /dev/null
+++ b/networking/udhcp/ChangeLog
@@ -0,0 +1,246 @@
10.9.8 (pending)
2+ udhcp now fits nicely into busybox
3 (Glenn McGrath <bug1@optushome.com.au> as well as myself)
4+ updated client manpage (me)
5+ both client and server now use sockets for signal handling,
6 hopefully, this will be the last needed change in signal
7 handling, I'm fairly certain all the possible races are now
8 closed. (me)
9+ The server now restarts the auto_time timer when it receives
10 a SIGUSR1 (write out config file). (me)
11+ Improve signal handling (David Poole)
12+ Fix to config file parsing (Matt Kraai)
13+ Fix load lease logic (me)
14+ Fix clear_lease logic (me)
15+ -h is now an alias for -H (udhcp bug #1253)
16+ Shorter timeout on not receiving offers (me)
17+ Improved signal behavior by client (me)
18+ Would never assign end address (Keith Smith <keith@ksmith.com>)
19+ Was improperly reporting yiaddr as siaddr (ben-udhcp@bdlow.net)
20 udhcp bug#1256
21+ Fixed reading of client id (David Poole <davep@portsmith.com>)
22+ change sys_errlist[] to strerror() as it aparently doesn't exist
23 (andersee <andersee@codepoet.org>)
24+ fixed get_raw_packet so it returns -2 on non fatal errors
25 (Ted Lemon <Ted.Lemon@nominum.com>)
26+ Improved (hopefully) NAKing behavior (me)
27+ Added -b option (Jouni Malinen)
28+ Compute checksums correctly on big endian hosts
29 (Jouni Malinen <jkmaline@cc.hut.fi>)
30
310.9.7 (020526)
32+ Use add_lease in read_leases, sanitizes leases more, and clears out exprired
33 ones if there is no more room (me)
34+ Moved udhcpd.leases to /var/lib/misc/udhcpd.leases (Debian bug #147747)
35+ Change (obsolete) AF_INET in arping.c to PF_PACKET (Debian bug #127049)
36+ Added script hook for DHCPNAK (nak), as well as providing the message option
37 (me)
38+ Generate the paramaters request list by seeing what options in options.c are
39 ored with OPTION_REQ in options.c
40+ Fix dhcp renew forgetfullness on client (bug #1230)
41+ Fix dhcp release bug on client (bug #1231)
42+ Set option request list for DHCP renew (bug #1233)
43+ Set BOOTREQUEST/REPLY properly
44+ Change client-identifier field to popularly expected behavior (me)
45+ Only reopen port on errors (me)
46+ Change fork/close/setsid structures to daemon() (me)
47+ Allow user to specify udhcpd config file at run time (Steven, me)
48+ Write pidfile after changing it (Steven CTR Carr <Steven.CTR.Carr@tc.faa.gov>)
49+ Added env var docs to udhcpc man page (Matt)
50+ Standardized lowercase udhcp in documentation (me)
51+ Accept packets without a UDP checksum (me)
52+ Accept packets with extra garbage (me)
53+ Better error handling in files.c (me)
54+ Combined read_interface function to reduce COMBINED_BINARY size (me)
55+ Drop calc_length(), some servers choke on smaller packets (me)
56+ Try to clean some fat out (me)
57
580.9.6 (011001)
59+ Added bootp paramaters to server (me)
60+ Added bootp paramaters to client (me)
61+ Added vendor id to client (me)
62+ Better pidfile handling in client and server (me)
63+ Added man pages (Matt Kraai <kraai@alumni.carnegiemellon.edu>)
64
650.9.5 (010914)
66+ Fixed $HOME and $PATH env passing (me)
67+ Fixed client to only listen for raw packets on correct interface (me)
68+ added --quit,-q option to quit after a lease is obtained (me)
69+ Fixed 100% CPU utilization by client when interface is down (me)
70
710.9.4 (010827)
72+ Force broadcast to broken clients that request unicast (ie, MSFT 98)
73+ Make install rules (Adam J. Richter <adam@yggdrasil.com>)
74+ One scripts, instead of many (Adam)
75+ Removed script paramater info files (env vars only) (Adam)
76+ Controlling of forking behavior in client (Adam)
77+ General script.c/dhcpc.c cleanups (Adam)
78
790.9.3 (010820)
80+ Increased debugging verbosity (me)
81+ Cut trailing whitespace when reading config file (me)
82+ added hostname option to client (me)
83+ fixed a strncpy bug in script.c (me)
84+ fixed a leaky socket in dhcpc.c (me)
85+ fixed a leaky socket in dhcpd.c (me)
86
870.9.2 (010810)
88+ Added raw sockets to client (me)
89+ alignment fixes (Mark Huang)
90+ compiler warning fixes (Mark Huang)
91+ client now sends parameter list (Mark Huang/me)
92+ added ipttl option
93+ Does now not request broadcast packets
94
950.9.1 (010806)
96+ Added udhcpc client
97+ reorganized functions/files
98+ listening socket now only binds to one interface
99
1000.9.0 (010720) Major rewrite, current changes, goals:
101+ should not segfault on bogus packets.
102+ Options can be read from sname and file fields.
103+ supports all DHCP messages (release, decline, inform).
104+ IP block is now specified by a range of IP's.
105+ Leases file now contains lease time (relative, or absolute).
106+ Just about any DHCP option is now supported.
107+ DNS entries are no longer read from resolv.conf
108+ Lease file can be written periodically when the process receives a SIGUSR1
109+ arpping should be supported on all arches.
110+ support for DHCP relays.
111+ DHCP messages can be unicast if the client requests it.
112+ many, many, many other things.
113
1140.8.29 (000323)
115+ stable(?) release
116
117
1180.8.28 (000323)
119+ removed alarm as it was causing server to go down
120+ removed debugging
121+ break down dhcpd.c into manageable files
122
123
1240.8.27 (000221)
125+ OFFER also sends gateway/subnet (for picky dhcp clients)
126+ multiple DNS now handled from resolv.conf if available
127+ multiple WINS (from dhcpd.conf)
128
1290.8.25 (000120)
130+ now compiles *and* runs on a generic linux system
131 tested with a windows 98 client and the sample config
132 files in the samples directory.
133
1340.8.24 (000117)
135+ makeiplist tool has basic functionality in place
136+ new sample config files
137+ route add -host 255.255.255.255 dev eth0 added for generic linux
138
1390.8.23 (000117)
140+ NETtel specific fix for ignoring dhcp requests on 2nd interface
141
1420.8.22 (000113)
143+ minor changes to compile under a generic linux system
144+ minor config file location changes for a generic linux system
145+ makeiplist fixes.. still incomplete.. but etting closer
146
1470.8.21 (000113)
148+ now sends the correct server ip instead of hardcoded value
149+ minor debugging fixes for critical messages
150
1510.8.20 (000106)
152+ cut out dhcp server checking.. this was causing dialout ppp
153 sessions with idle time set to never time out.
154+ also removed the 10 second pause before launching.. as this
155 was originally to stop it replying to a dhcp client
156 on a NETtel which was really a bad way to do it in the
157 first place :-)
158
1590.8.19 (000104)
160+ fixes for route add -host on a machine that needs to run both
161 a DHCP client and server (dual eth box)
162
1630.8.18 (991220)
164
165+ Race conditions fixed by disabling alarm whilst the server is busy
166+ Fixed continous clearing of the offered array so that it is only cleared
167 when it is dirty - (could change the position of when dirty is set)
168
1690.8.17 (991212)
170
171- has problems clearing out the offered array
172
1730.8.16 (991203)
174+ Non blocking error is changes to informational as it is not really
175 an error
176
1770.8.15 (991129)
178+ Servs the dns field 3 times (Nettel only) so that windows servers
179 dont time out whilst nettel is booting
180
1810.8.14 (991126)
182+ added owner check for the offered array so clean out time may be
183 increased
184+ added new func to print out chadder/MAC
185
1860.8.13 (991125)
187+ added win95 support (w95 changed xid halfway through conversation)
188+ had to change the offered array to use hardware addresses instead of xid
189+ fixed re offered bug
190+ added more debugging
191
1920.8.12 (991111)
193+ debugging was real bad.. cleaned up a bit.. needs overhaul
194
195
1960.8.11 (991110)
197+ fixed up offeredAddr array to actually be used now!! offeredAddr is
198 used to see if another simultaneous connecting client was offered
199 an address that we are about to offer another client (multiple
200 client bug)
201+ removed re_offered variable as it breaks multiple client support
202+ added lease time to ACK -- doesn't work if in OFFER
203+ decreased internal array clear delay to 60 seconds
204+ minor findAddr bug (returning -1 instead of 0)
205+ if clients xid already in offeredAddr offer the same addr and don't add a
206 new addr to offered (caused by a client issuing multiple DISCOVERs)
207
2080.8.10 (991105)
209+ \n bug in arpping
210+ minor debugging changes (removed printfs etc)
211+ started browseiplist (not finished)
212
2130.8.9 (19991105)
214+ fixed options array size bug (options were cut off)
215
2160.8.8 (19991105)
217+ ignores requests from dhcpcd on the same machine
218
2190.8.7 (19991104)
220+ don't die if we can't bind to search for existing DHCP server
221+ slightly more verbose syslogging
222
2230.8.6 (19991103)
224+ added makeiplist (not finished -- core dumps)
225+ minor debug changes
226
2270.8.5 (19991029)
228+ exits if another DHCP server is already on the network
229+ added Linux Makefile
230
2310.8.4 (19991026)
232+ minor bug fix in findaddr preventing an addr being found
233
2340.8.3 (19991025)
235+ fixed up debugging
236+ minor hwaddr issues
237
2380.8.2 (19991022)
239+ free leases (new arpping code from dhcpcd)
240+ fixed bug where crashes if no leases/iplist file
241+ syslogging and debugging switch
242+ serve DNS from resolv.conf
243+ fixed bug where new lease added if same mac offered
244+ now checks the ip is free b4 offering
245+ now supports wins server
246
diff --git a/networking/udhcp/Makefile.in b/networking/udhcp/Makefile.in
new file mode 100644
index 000000000..d76715baa
--- /dev/null
+++ b/networking/udhcp/Makefile.in
@@ -0,0 +1,46 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20UDHCP_AR:=udhcp.a
21ifndef $(UDHCP_DIR)
22UDHCP_DIR:=$(TOPDIR)networking/udhcp/
23endif
24
25#ok, so I forgot how to do an or, but this is a quick and dirty hack
26ifeq ($(CONFIG_UDHCPC), y)
27CONFIG_UDHCP_SHARED=y
28else
29ifeq ($(CONFIG_UDHCPD), y)
30CONFIG_UDHCP_SHARED=y
31else
32CONFIG_UDHCP_SHARED=n
33endif
34endif
35
36UDHCP-y:=
37UDHCP-$(CONFIG_UDHCP_SHARED) += options.o socket.o packet.o pidfile.o
38UDHCP-$(CONFIG_UDHCPC) += dhcpc.o clientpacket.o script.o
39UDHCP-$(CONFIG_UDHCPD) += dhcpd.o arpping.o files.o leases.o serverpacket.o
40UDHCP-$(CONFIG_DUMPLEASES) += dumpleases.o
41
42libraries-y+=$(UDHCP_DIR)$(UDHCP_AR)
43
44$(UDHCP_DIR)$(UDHCP_AR): $(patsubst %,$(UDHCP_DIR)%, $(UDHCP-y))
45 $(AR) -ro $@ $(patsubst %,$(UDHCP_DIR)%, $(UDHCP-y))
46
diff --git a/networking/udhcp/README b/networking/udhcp/README
new file mode 100644
index 000000000..d3e5e3fbc
--- /dev/null
+++ b/networking/udhcp/README
@@ -0,0 +1,197 @@
1udhcp server/client package readme
2-------------------------
3
4The udhcp server/client package is primarily geared towards embedded
5systems. It does however, strive to be fully functional, and RFC
6compliant.
7
8udhcp server (udhcpd)
9--------------------
10
11The only command line argument to udhcpd is an optional specifed
12config file. If no config file is specified, udhcpd uses the default
13config file, /etc/udhcpd.conf. Ex:
14
15udhcpd /etc/udhcpd.eth1.conf
16
17The udhcp server employs a number of simple config files:
18
19udhcpd.leases
20------------
21
22The udhcpd.leases behavior is designed for an embedded system. The
23file is written either every auto_time seconds, or when a SIGUSR1
24is received (the auto_time timer restarts if a SIGUSR1 is received).
25If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will
26finish writing the leases file and wait for the aftermentioned script
27to be executed and finish before quiting, so you do not need to sleep
28between sending signals. When the file is written, a script can be
29optionally called to commit the file to flash. Lease times are stored
30in the file by time remaining in lease (for systems without clock
31that works when there is no power), or by the absolute time that it
32expires in seconds from epoch. In the remainig format, expired leases
33are stored as zero. The file is of the format:
34
3516 byte MAC
364 byte ip address
37u32 expire time
3816 byte MAC
394 byte ip address
40u32 expire time
41.
42etc.
43
44example: hexdump udhcpd.leases
45
460000000 1000 c95a 27d9 0000 0000 0000 0000 0000
470000010 a8c0 150a 0d00 2d29 5000 23fc 8566 0000
480000020 0000 0000 0000 0000 a8c0 140a 0d00 4e29
490000030
50
51
52udhcpd.conf
53----------
54
55The format is fairly simple, there is a sample file with all the
56available options and comments describing them in samples/udhcpd.conf
57
58
59udhcp client (udhcpc)
60--------------------
61
62The udhcp client negotiates a lease with the DHCP server and notifies
63a set of scripts when a leases is obtained or lost. The command line
64options for the udhcp client are:
65
66-c, --clientid=CLIENTID Client identifier
67-H, --hostname=HOSTNAME Client hostname
68-h, Alias for -H
69-f, --foreground Do not fork after getting lease
70-b, --background Fork to background if lease cannot be
71 immediately negotiated.
72-i, --interface=INTERFACE Interface to use (default: eth0)
73-n, --now Exit with failure if lease cannot be
74 immediately negotiated.
75-p, --pidfile=file Store process ID of daemon in file
76-q, --quit Quit after obtaining lease
77-r, --request=IP IP address to request (default: none)
78-s, --script=file Run file at dhcp events (default:
79 /usr/share/udhcpc/default.script)
80-v, --version Display version
81
82If the requested IP address cannot be obtained, the client accepts the
83address that the server offers.
84
85When an event occurs, udhcpc calls the action script. The script by
86default is /usr/share/udhcpc/default.script but this can be changed via
87the command line arguments. The three possible arguments to the script
88are:
89
90 deconfig: This argument is used when udhcpc starts, and
91 when a leases is lost. The script should put the interface in an
92 up, but deconfigured state, ie: ifconfig $interface 0.0.0.0.
93
94 bound: This argument is used when udhcpc moves from an
95 unbound, to a bound state. All of the paramaters are set in
96 enviromental variables, The script should configure the interface,
97 and set any other relavent parameters (default gateway, dns server,
98 etc).
99
100 renew: This argument is used when a DHCP lease is renewed. All of
101 the paramaters are set in enviromental variables. This argument is
102 used when the interface is already configured, so the IP address,
103 will not change, however, the other DHCP paramaters, such as the
104 default gateway, subnet mask, and dns server may change.
105
106 nak: This argument is used with udhcpc receives a NAK message.
107 The script with the deconfig argument will be called directly
108 afterwards, so no changes to the network interface are neccessary.
109 This hook is provided for purely informational purposes (the
110 message option may contain a reason for the NAK).
111
112The paramaters for enviromental variables are as follows:
113
114 $HOME - The set $HOME env or "/"
115 $PATH - the set $PATH env or "/bin:/usr/bin:/sbin:/usr/sbin"
116 $1 - What action the script should perform
117 interface - The interface this was obtained on
118 ip - The obtained IP
119 siaddr - The bootp next server option
120 sname - The bootp server name option
121 boot_file - The bootp boot file option
122 subnet - The assigend subnet mask
123 timezone - Offset in seconds from UTC
124 router - A list of routers
125 timesvr - A list of time servers
126 namesvr - A list of IEN 116 name servers
127 dns - A list of DNS server
128 logsvr - A list of MIT-LCS UDP log servers
129 cookiesvr - A list of RFC 865 cookie servers
130 lprsvr - A list of LPR servers
131 hostname - The assigned hostname
132 bootsize - The length in 512 octect blocks of the bootfile
133 domain - The domain name of the network
134 swapsvr - The IP address of the client's swap server
135 rootpath - The path name of the client's root disk
136 ipttl - The TTL to use for this network
137 mtu - The MTU to use for this network
138 broadcast - The broadcast address for this network
139 ntpsrv - A list of NTP servers
140 wins - A list of WINS servers
141 lease - The lease time, in seconds
142 dhcptype - DHCP message type (safely ignored)
143 serverid - The IP of the server
144 message - Reason for a DHCPNAK
145 tftp - The TFTP server name
146 bootfile - The bootfile name
147
148additional options are easily added in options.c.
149
150udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state,
151and SIGUSR2 will force a release of the current lease, and cause udhcpc to
152go into an inactive state (until it is killed, or receives a SIGUSR1). You do
153not need to sleep between sending signals, as signals received are processed
154sequencially in the order they are received.
155
156
157
158compile time options
159-------------------
160
161The Makefile contains three of the compile time options:
162
163 DEBUG: If DEBUG is defined, udhcpd will output extra debugging
164 output, compile with -g, and not fork to the background when run.
165 SYSLOG: If SYSLOG is defined, udhcpd will log all its messages
166 syslog, otherwise, it will attempt to log them to stdout.
167
168 COMBINED_BINARY: If COMBINED_BINARY is define, one binary, udhcpd,
169 is created. If called as udhcpd, the dhcp server will be started.
170 If called as udhcpc, the dhcp client will be started.
171
172dhcpd.h contains the other two compile time options:
173
174 LEASE_TIME: The default lease time if not specified in the config
175 file.
176
177 DHCPD_CONFIG_FILE: The defualt config file to use.
178
179options.c contains a set of dhcp options for the client:
180
181 name[10]: The name of the option as it will appear in scripts
182
183 flags: The type of option, as well as if it will be requested
184 by the client (OPTION_REQ)
185
186 code: The DHCP code for this option
187
188busybox drop-in
189--------------
190udhcp is now a drop-in component for busybox (http://busybox.net).
191To update busybox to the latest revision, simply do a:
192
193cp *.[ch] README AUTHORS COPYING ChangeLog TODO \
194 <busybox_source>/networking/udhcp
195
196The only two files udhcp does not provide are config.in and
197Makefile.in, so these may need to be updated from time to time.
diff --git a/networking/udhcp/TODO b/networking/udhcp/TODO
new file mode 100644
index 000000000..47e451213
--- /dev/null
+++ b/networking/udhcp/TODO
@@ -0,0 +1,17 @@
1TODO
2----
3+ make failure of reading functions revert to previous value, not the default
4+ sanity code for option[OPT_LEN]
5+ fix aliasing (ie: eth0:0)
6+ DONE: Make sure get_raw_packet only accepts packets on the specified interface
7+ better standard linux distro support
8+ DONE: make config file a command line option for server
9+ IMPLEMENTED: make forking a command line option
10+ make sure packet generation works on a wide varitey of arches
11+ Interoperability testing
12+ Hooks within the DHCP server
13+ Additional bootp support in client/server
14+ Make serverid option in server configurable
15+ DONE: cause client to generate DHCP_VENDOR option
16+ Possibly add failure message to DHCP NAK
17+ Possibly log DHCP NAK failure message in client \ No newline at end of file
diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c
new file mode 100644
index 000000000..d71cd10f4
--- /dev/null
+++ b/networking/udhcp/arpping.c
@@ -0,0 +1,105 @@
1/*
2 * arpping.c
3 *
4 * Mostly stolen from: dhcpcd - DHCP client daemon
5 * by Yoichi Hariguchi <yoichi@fore.com>
6 */
7
8#include <sys/types.h>
9#include <sys/time.h>
10#include <time.h>
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <netinet/if_ether.h>
14#include <net/if_arp.h>
15#include <netinet/in.h>
16#include <stdio.h>
17#include <string.h>
18#include <unistd.h>
19#include <errno.h>
20
21#include "dhcpd.h"
22#include "debug.h"
23#include "arpping.h"
24
25/* args: yiaddr - what IP to ping
26 * ip - our ip
27 * mac - our arp address
28 * interface - interface to use
29 * retn: 1 addr free
30 * 0 addr used
31 * -1 error
32 */
33
34/* FIXME: match response against chaddr */
35int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *mac, char *interface)
36{
37
38 int timeout = 2;
39 int optval = 1;
40 int s; /* socket */
41 int rv = 1; /* return value */
42 struct sockaddr addr; /* for interface name */
43 struct arpMsg arp;
44 fd_set fdset;
45 struct timeval tm;
46 time_t prevTime;
47
48
49 if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) {
50 LOG(LOG_ERR, "Could not open raw socket");
51 return -1;
52 }
53
54 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
55 LOG(LOG_ERR, "Could not setsocketopt on raw socket");
56 close(s);
57 return -1;
58 }
59
60 /* send arp request */
61 memset(&arp, 0, sizeof(arp));
62 memcpy(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */
63 memcpy(arp.ethhdr.h_source, mac, 6); /* MAC SA */
64 arp.ethhdr.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
65 arp.htype = htons(ARPHRD_ETHER); /* hardware type */
66 arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
67 arp.hlen = 6; /* hardware address length */
68 arp.plen = 4; /* protocol address length */
69 arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
70 *((u_int *) arp.sInaddr) = ip; /* source IP address */
71 memcpy(arp.sHaddr, mac, 6); /* source hardware address */
72 *((u_int *) arp.tInaddr) = yiaddr; /* target IP address */
73
74 memset(&addr, 0, sizeof(addr));
75 strcpy(addr.sa_data, interface);
76 if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
77 rv = 0;
78
79 /* wait arp reply, and check it */
80 tm.tv_usec = 0;
81 time(&prevTime);
82 while (timeout > 0) {
83 FD_ZERO(&fdset);
84 FD_SET(s, &fdset);
85 tm.tv_sec = timeout;
86 if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) {
87 DEBUG(LOG_ERR, "Error on ARPING request: %s", strerror(errno));
88 if (errno != EINTR) rv = 0;
89 } else if (FD_ISSET(s, &fdset)) {
90 if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;
91 if (arp.operation == htons(ARPOP_REPLY) &&
92 bcmp(arp.tHaddr, mac, 6) == 0 &&
93 *((u_int *) arp.sInaddr) == yiaddr) {
94 DEBUG(LOG_INFO, "Valid arp reply receved for this address");
95 rv = 0;
96 break;
97 }
98 }
99 timeout -= time(NULL) - prevTime;
100 time(&prevTime);
101 }
102 close(s);
103 DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");
104 return rv;
105}
diff --git a/networking/udhcp/arpping.h b/networking/udhcp/arpping.h
new file mode 100644
index 000000000..92b828db5
--- /dev/null
+++ b/networking/udhcp/arpping.h
@@ -0,0 +1,30 @@
1/*
2 * arpping .h
3 */
4
5#ifndef ARPPING_H
6#define ARPPING_H
7
8#include <netinet/if_ether.h>
9#include <net/if_arp.h>
10#include <net/if.h>
11#include <netinet/in.h>
12
13struct arpMsg {
14 struct ethhdr ethhdr; /* Ethernet header */
15 u_short htype; /* hardware type (must be ARPHRD_ETHER) */
16 u_short ptype; /* protocol type (must be ETH_P_IP) */
17 u_char hlen; /* hardware address length (must be 6) */
18 u_char plen; /* protocol address length (must be 4) */
19 u_short operation; /* ARP opcode */
20 u_char sHaddr[6]; /* sender's hardware address */
21 u_char sInaddr[4]; /* sender's IP address */
22 u_char tHaddr[6]; /* target's hardware address */
23 u_char tInaddr[4]; /* target's IP address */
24 u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
25};
26
27/* function prototypes */
28int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *arp, char *interface);
29
30#endif
diff --git a/networking/udhcp/clientpacket.c b/networking/udhcp/clientpacket.c
new file mode 100644
index 000000000..ecbd7953f
--- /dev/null
+++ b/networking/udhcp/clientpacket.c
@@ -0,0 +1,239 @@
1/* clientpacket.c
2 *
3 * Packet generation and dispatching functions for the DHCP client.
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <string.h>
23#include <sys/socket.h>
24#include <features.h>
25#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
26#include <netpacket/packet.h>
27#include <net/ethernet.h>
28#else
29#include <asm/types.h>
30#include <linux/if_packet.h>
31#include <linux/if_ether.h>
32#endif
33#include <stdlib.h>
34#include <time.h>
35#include <unistd.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38
39
40#include "dhcpd.h"
41#include "packet.h"
42#include "options.h"
43#include "dhcpc.h"
44#include "debug.h"
45
46
47/* Create a random xid */
48unsigned long random_xid(void)
49{
50 static int initialized;
51 if (!initialized) {
52 srand(time(0));
53 initialized++;
54 }
55 return rand();
56}
57
58
59/* initialize a packet with the proper defaults */
60static void init_packet(struct dhcpMessage *packet, char type)
61{
62 struct vendor {
63 char vendor, length;
64 char str[sizeof("udhcp "VERSION)];
65 } vendor_id = { DHCP_VENDOR, sizeof("udhcp "VERSION) - 1, "udhcp "VERSION};
66
67 init_header(packet, type);
68 memcpy(packet->chaddr, client_config.arp, 6);
69 add_option_string(packet->options, client_config.clientid);
70 if (client_config.hostname) add_option_string(packet->options, client_config.hostname);
71 add_option_string(packet->options, (unsigned char *) &vendor_id);
72}
73
74
75/* Add a paramater request list for stubborn DHCP servers. Pull the data
76 * from the struct in options.c. Don't do bounds checking here because it
77 * goes towards the head of the packet. */
78static void add_requests(struct dhcpMessage *packet)
79{
80 int end = end_option(packet->options);
81 int i, len = 0;
82
83 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
84 for (i = 0; options[i].code; i++)
85 if (options[i].flags & OPTION_REQ)
86 packet->options[end + OPT_DATA + len++] = options[i].code;
87 packet->options[end + OPT_LEN] = len;
88 packet->options[end + OPT_DATA + len] = DHCP_END;
89
90}
91
92
93/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
94int send_discover(unsigned long xid, unsigned long requested)
95{
96 struct dhcpMessage packet;
97
98 init_packet(&packet, DHCPDISCOVER);
99 packet.xid = xid;
100 if (requested)
101 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
102
103 add_requests(&packet);
104 LOG(LOG_DEBUG, "Sending discover...");
105 return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
106 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
107}
108
109
110/* Broadcasts a DHCP request message */
111int send_selecting(unsigned long xid, unsigned long server, unsigned long requested)
112{
113 struct dhcpMessage packet;
114 struct in_addr addr;
115
116 init_packet(&packet, DHCPREQUEST);
117 packet.xid = xid;
118
119 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
120 add_simple_option(packet.options, DHCP_SERVER_ID, server);
121
122 add_requests(&packet);
123 addr.s_addr = requested;
124 LOG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr));
125 return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
126 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
127}
128
129
130/* Unicasts or broadcasts a DHCP renew message */
131int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr)
132{
133 struct dhcpMessage packet;
134 int ret = 0;
135
136 init_packet(&packet, DHCPREQUEST);
137 packet.xid = xid;
138 packet.ciaddr = ciaddr;
139
140 add_requests(&packet);
141 LOG(LOG_DEBUG, "Sending renew...");
142 if (server)
143 ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
144 else ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
145 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
146 return ret;
147}
148
149
150/* Unicasts a DHCP release message */
151int send_release(unsigned long server, unsigned long ciaddr)
152{
153 struct dhcpMessage packet;
154
155 init_packet(&packet, DHCPRELEASE);
156 packet.xid = random_xid();
157 packet.ciaddr = ciaddr;
158
159 add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr);
160 add_simple_option(packet.options, DHCP_SERVER_ID, server);
161
162 LOG(LOG_DEBUG, "Sending release...");
163 return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
164}
165
166
167/* return -1 on errors that are fatal for the socket, -2 for those that aren't */
168int get_raw_packet(struct dhcpMessage *payload, int fd)
169{
170 int bytes;
171 struct udp_dhcp_packet packet;
172 u_int32_t source, dest;
173 u_int16_t check;
174
175 memset(&packet, 0, sizeof(struct udp_dhcp_packet));
176 bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
177 if (bytes < 0) {
178 DEBUG(LOG_INFO, "couldn't read on raw listening socket -- ignoring");
179 usleep(500000); /* possible down interface, looping condition */
180 return -1;
181 }
182
183 if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
184 DEBUG(LOG_INFO, "message too short, ignoring");
185 return -2;
186 }
187
188 if (bytes < ntohs(packet.ip.tot_len)) {
189 DEBUG(LOG_INFO, "Truncated packet");
190 return -2;
191 }
192
193 /* ignore any extra garbage bytes */
194 bytes = ntohs(packet.ip.tot_len);
195
196 /* Make sure its the right packet for us, and that it passes sanity checks */
197 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION ||
198 packet.ip.ihl != sizeof(packet.ip) >> 2 || packet.udp.dest != htons(CLIENT_PORT) ||
199 bytes > (int) sizeof(struct udp_dhcp_packet) ||
200 ntohs(packet.udp.len) != (short) (bytes - sizeof(packet.ip))) {
201 DEBUG(LOG_INFO, "unrelated/bogus packet");
202 return -2;
203 }
204
205 /* check IP checksum */
206 check = packet.ip.check;
207 packet.ip.check = 0;
208 if (check != checksum(&(packet.ip), sizeof(packet.ip))) {
209 DEBUG(LOG_INFO, "bad IP header checksum, ignoring");
210 return -1;
211 }
212
213 /* verify the UDP checksum by replacing the header with a psuedo header */
214 source = packet.ip.saddr;
215 dest = packet.ip.daddr;
216 check = packet.udp.check;
217 packet.udp.check = 0;
218 memset(&packet.ip, 0, sizeof(packet.ip));
219
220 packet.ip.protocol = IPPROTO_UDP;
221 packet.ip.saddr = source;
222 packet.ip.daddr = dest;
223 packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
224 if (check && check != checksum(&packet, bytes)) {
225 DEBUG(LOG_ERR, "packet with bad UDP checksum received, ignoring");
226 return -2;
227 }
228
229 memcpy(payload, &(packet.data), bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
230
231 if (ntohl(payload->cookie) != DHCP_MAGIC) {
232 LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring");
233 return -2;
234 }
235 DEBUG(LOG_INFO, "oooooh!!! got some!");
236 return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
237
238}
239
diff --git a/networking/udhcp/clientpacket.h b/networking/udhcp/clientpacket.h
new file mode 100644
index 000000000..2a6facbc8
--- /dev/null
+++ b/networking/udhcp/clientpacket.h
@@ -0,0 +1,12 @@
1#ifndef _CLIENTPACKET_H
2#define _CLIENTPACKET_H
3
4unsigned long random_xid(void);
5int send_discover(unsigned long xid, unsigned long requested);
6int send_selecting(unsigned long xid, unsigned long server, unsigned long requested);
7int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
8int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
9int send_release(unsigned long server, unsigned long ciaddr);
10int get_raw_packet(struct dhcpMessage *payload, int fd);
11
12#endif
diff --git a/networking/udhcp/config.in b/networking/udhcp/config.in
new file mode 100644
index 000000000..ede632a8a
--- /dev/null
+++ b/networking/udhcp/config.in
@@ -0,0 +1,18 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'udhcp Server/Client'
8
9bool 'udhcp Server (udhcpd)' CONFIG_UDHCPD
10bool 'udhcp Client (udhcpc)' CONFIG_UDHCPC
11bool 'Lease display utility (dumpleases)' CONFIG_DUMPLEASES
12if [ "$CONFIG_UDHCPD" = "y" -o "$CONFIG_UDHCPC" = "y" ]; then
13 bool ' Log udhcp messages to syslog (instead of stdout)' CONFIG_FEATURE_UDHCP_SYSLOG
14 bool ' Compile udhcp with noisy debugging messages' CONFIG_FEATURE_UDHCP_DEBUG
15fi
16
17endmenu
18
diff --git a/networking/udhcp/debug.h b/networking/udhcp/debug.h
new file mode 100644
index 000000000..a1e197412
--- /dev/null
+++ b/networking/udhcp/debug.h
@@ -0,0 +1,41 @@
1#ifndef _DEBUG_H
2#define _DEBUG_H
3
4#include "libbb_udhcp.h"
5
6#include <stdio.h>
7#ifdef SYSLOG
8#include <syslog.h>
9#endif
10
11
12#ifdef SYSLOG
13# define LOG(level, str, args...) do { printf(str, ## args); \
14 printf("\n"); \
15 syslog(level, str, ## args); } while(0)
16# define OPEN_LOG(name) openlog(name, 0, 0)
17#define CLOSE_LOG() closelog()
18#else
19# define LOG_EMERG "EMERGENCY!"
20# define LOG_ALERT "ALERT!"
21# define LOG_CRIT "critical!"
22# define LOG_WARNING "warning"
23# define LOG_ERR "error"
24# define LOG_INFO "info"
25# define LOG_DEBUG "debug"
26# define LOG(level, str, args...) do { printf("%s, ", level); \
27 printf(str, ## args); \
28 printf("\n"); } while(0)
29# define OPEN_LOG(name) do {;} while(0)
30#define CLOSE_LOG() do {;} while(0)
31#endif
32
33#ifdef DEBUG
34# undef DEBUG
35# define DEBUG(level, str, args...) LOG(level, str, ## args)
36# define DEBUGGING
37#else
38# define DEBUG(level, str, args...) do {;} while(0)
39#endif
40
41#endif
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
new file mode 100644
index 000000000..ae40ec9c2
--- /dev/null
+++ b/networking/udhcp/dhcpc.c
@@ -0,0 +1,559 @@
1/* dhcpc.c
2 *
3 * udhcp DHCP client
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <stdio.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <sys/file.h>
26#include <unistd.h>
27#include <getopt.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <signal.h>
33#include <time.h>
34#include <string.h>
35#include <sys/ioctl.h>
36#include <net/if.h>
37#include <errno.h>
38
39#include "dhcpd.h"
40#include "dhcpc.h"
41#include "options.h"
42#include "clientpacket.h"
43#include "packet.h"
44#include "script.h"
45#include "socket.h"
46#include "debug.h"
47#include "pidfile.h"
48
49static int state;
50static unsigned long requested_ip; /* = 0 */
51static unsigned long server_addr;
52static unsigned long timeout;
53static int packet_num; /* = 0 */
54static int fd;
55static int signal_pipe[2];
56
57#define LISTEN_NONE 0
58#define LISTEN_KERNEL 1
59#define LISTEN_RAW 2
60static int listen_mode;
61
62#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
63
64struct client_config_t client_config = {
65 /* Default options. */
66 abort_if_no_lease: 0,
67 foreground: 0,
68 quit_after_lease: 0,
69 background_if_no_lease: 0,
70 interface: "eth0",
71 pidfile: NULL,
72 script: DEFAULT_SCRIPT,
73 clientid: NULL,
74 hostname: NULL,
75 ifindex: 0,
76 arp: "\0\0\0\0\0\0", /* appease gcc-3.0 */
77};
78
79#ifndef BB_VER
80static void show_usage(void)
81{
82 printf(
83"Usage: udhcpc [OPTIONS]\n\n"
84" -c, --clientid=CLIENTID Client identifier\n"
85" -H, --hostname=HOSTNAME Client hostname\n"
86" -h Alias for -H\n"
87" -f, --foreground Do not fork after getting lease\n"
88" -b, --background Fork to background if lease cannot be\n"
89" immediately negotiated.\n"
90" -i, --interface=INTERFACE Interface to use (default: eth0)\n"
91" -n, --now Exit with failure if lease cannot be\n"
92" immediately negotiated.\n"
93" -p, --pidfile=file Store process ID of daemon in file\n"
94" -q, --quit Quit after obtaining lease\n"
95" -r, --request=IP IP address to request (default: none)\n"
96" -s, --script=file Run file at dhcp events (default:\n"
97" " DEFAULT_SCRIPT ")\n"
98" -v, --version Display version\n"
99 );
100 exit(0);
101}
102#endif
103
104
105/* just a little helper */
106static void change_mode(int new_mode)
107{
108 DEBUG(LOG_INFO, "entering %s listen mode",
109 new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
110 close(fd);
111 fd = -1;
112 listen_mode = new_mode;
113}
114
115
116/* perform a renew */
117static void perform_renew(void)
118{
119 LOG(LOG_INFO, "Performing a DHCP renew");
120 switch (state) {
121 case RENEWING:
122 run_script(NULL, "deconfig");
123 case BOUND:
124 case REBINDING:
125 change_mode(LISTEN_KERNEL);
126 state = RENEW_REQUESTED;
127 break;
128 case RENEW_REQUESTED:
129 case REQUESTING:
130 case RELEASED:
131 change_mode(LISTEN_RAW);
132 state = INIT_SELECTING;
133 break;
134 case INIT_SELECTING:
135 }
136
137 /* start things over */
138 packet_num = 0;
139
140 /* Kill any timeouts because the user wants this to hurry along */
141 timeout = 0;
142}
143
144
145/* perform a release */
146static void perform_release(void)
147{
148 char buffer[16];
149 struct in_addr temp_addr;
150
151 /* send release packet */
152 if (state == BOUND || state == RENEWING || state == REBINDING) {
153 temp_addr.s_addr = server_addr;
154 sprintf(buffer, "%s", inet_ntoa(temp_addr));
155 temp_addr.s_addr = requested_ip;
156 LOG(LOG_INFO, "Unicasting a release of %s to %s",
157 inet_ntoa(temp_addr), buffer);
158 send_release(server_addr, requested_ip); /* unicast */
159 run_script(NULL, "deconfig");
160 }
161 LOG(LOG_INFO, "Entering released state");
162
163 change_mode(LISTEN_NONE);
164 state = RELEASED;
165 timeout = 0x7fffffff;
166}
167
168
169/* Exit and cleanup */
170static void exit_client(int retval)
171{
172 pidfile_delete(client_config.pidfile);
173 CLOSE_LOG();
174 exit(retval);
175}
176
177
178/* Signal handler */
179static void signal_handler(int sig)
180{
181 if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
182 LOG(LOG_ERR, "Could not send signal: %s",
183 strerror(errno));
184 }
185}
186
187
188static void background(void)
189{
190 int pid_fd;
191
192 pid_fd = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
193 while (pid_fd >= 0 && pid_fd < 3) pid_fd = dup(pid_fd); /* don't let daemon close it */
194 if (daemon(0, 0) == -1) {
195 perror("fork");
196 exit_client(1);
197 }
198 client_config.foreground = 1; /* Do not fork again. */
199 pidfile_write_release(pid_fd);
200}
201
202
203#ifdef COMBINED_BINARY
204int udhcpc_main(int argc, char *argv[])
205#else
206int main(int argc, char *argv[])
207#endif
208{
209 unsigned char *temp, *message;
210 unsigned long t1 = 0, t2 = 0, xid = 0;
211 unsigned long start = 0, lease;
212 fd_set rfds;
213 int retval;
214 struct timeval tv;
215 int c, len;
216 struct dhcpMessage packet;
217 struct in_addr temp_addr;
218 int pid_fd;
219 time_t now;
220 int max_fd;
221 int sig;
222
223 static struct option arg_options[] = {
224 {"clientid", required_argument, 0, 'c'},
225 {"foreground", no_argument, 0, 'f'},
226 {"background", no_argument, 0, 'b'},
227 {"hostname", required_argument, 0, 'H'},
228 {"hostname", required_argument, 0, 'h'},
229 {"interface", required_argument, 0, 'i'},
230 {"now", no_argument, 0, 'n'},
231 {"pidfile", required_argument, 0, 'p'},
232 {"quit", no_argument, 0, 'q'},
233 {"request", required_argument, 0, 'r'},
234 {"script", required_argument, 0, 's'},
235 {"version", no_argument, 0, 'v'},
236 {"help", no_argument, 0, '?'},
237 {0, 0, 0, 0}
238 };
239
240 /* get options */
241 while (1) {
242 int option_index = 0;
243 c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
244 if (c == -1) break;
245
246 switch (c) {
247 case 'c':
248 len = strlen(optarg) > 255 ? 255 : strlen(optarg);
249 if (client_config.clientid) free(client_config.clientid);
250 client_config.clientid = xmalloc(len + 2);
251 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
252 client_config.clientid[OPT_LEN] = len;
253 client_config.clientid[OPT_DATA] = '\0';
254 strncpy(client_config.clientid + OPT_DATA, optarg, len);
255 break;
256 case 'f':
257 client_config.foreground = 1;
258 break;
259 case 'b':
260 client_config.background_if_no_lease = 1;
261 break;
262 case 'h':
263 case 'H':
264 len = strlen(optarg) > 255 ? 255 : strlen(optarg);
265 if (client_config.hostname) free(client_config.hostname);
266 client_config.hostname = xmalloc(len + 2);
267 client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
268 client_config.hostname[OPT_LEN] = len;
269 strncpy(client_config.hostname + 2, optarg, len);
270 break;
271 case 'i':
272 client_config.interface = optarg;
273 break;
274 case 'n':
275 client_config.abort_if_no_lease = 1;
276 break;
277 case 'p':
278 client_config.pidfile = optarg;
279 break;
280 case 'q':
281 client_config.quit_after_lease = 1;
282 break;
283 case 'r':
284 requested_ip = inet_addr(optarg);
285 break;
286 case 's':
287 client_config.script = optarg;
288 break;
289 case 'v':
290 printf("udhcpcd, version %s\n\n", VERSION);
291 exit_client(0);
292 break;
293 default:
294 show_usage();
295 }
296 }
297
298 OPEN_LOG("udhcpc");
299 LOG(LOG_INFO, "udhcp client (v%s) started", VERSION);
300
301 pid_fd = pidfile_acquire(client_config.pidfile);
302 pidfile_write_release(pid_fd);
303
304 if (read_interface(client_config.interface, &client_config.ifindex,
305 NULL, client_config.arp) < 0)
306 exit_client(1);
307
308 if (!client_config.clientid) {
309 client_config.clientid = xmalloc(6 + 3);
310 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
311 client_config.clientid[OPT_LEN] = 7;
312 client_config.clientid[OPT_DATA] = 1;
313 memcpy(client_config.clientid + 3, client_config.arp, 6);
314 }
315
316 /* setup signal handlers */
317 socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
318 signal(SIGUSR1, signal_handler);
319 signal(SIGUSR2, signal_handler);
320 signal(SIGTERM, signal_handler);
321
322 state = INIT_SELECTING;
323 run_script(NULL, "deconfig");
324 change_mode(LISTEN_RAW);
325
326 for (;;) {
327
328 tv.tv_sec = timeout - time(0);
329 tv.tv_usec = 0;
330 FD_ZERO(&rfds);
331
332 if (listen_mode != LISTEN_NONE && fd < 0) {
333 if (listen_mode == LISTEN_KERNEL)
334 fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
335 else
336 fd = raw_socket(client_config.ifindex);
337 if (fd < 0) {
338 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno));
339 exit_client(0);
340 }
341 }
342 if (fd >= 0) FD_SET(fd, &rfds);
343 FD_SET(signal_pipe[0], &rfds);
344
345 if (tv.tv_sec > 0) {
346 DEBUG(LOG_INFO, "Waiting on select...\n");
347 max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
348 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
349 } else retval = 0; /* If we already timed out, fall through */
350
351 now = time(0);
352 if (retval == 0) {
353 /* timeout dropped to zero */
354 switch (state) {
355 case INIT_SELECTING:
356 if (packet_num < 3) {
357 if (packet_num == 0)
358 xid = random_xid();
359
360 /* send discover packet */
361 send_discover(xid, requested_ip); /* broadcast */
362
363 timeout = now + ((packet_num == 2) ? 4 : 2);
364 packet_num++;
365 } else {
366 if (client_config.background_if_no_lease) {
367 LOG(LOG_INFO, "No lease, forking to background.");
368 background();
369 } else if (client_config.abort_if_no_lease) {
370 LOG(LOG_INFO, "No lease, failing.");
371 exit_client(1);
372 }
373 /* wait to try again */
374 packet_num = 0;
375 timeout = now + 60;
376 }
377 break;
378 case RENEW_REQUESTED:
379 case REQUESTING:
380 if (packet_num < 3) {
381 /* send request packet */
382 if (state == RENEW_REQUESTED)
383 send_renew(xid, server_addr, requested_ip); /* unicast */
384 else send_selecting(xid, server_addr, requested_ip); /* broadcast */
385
386 timeout = now + ((packet_num == 2) ? 10 : 2);
387 packet_num++;
388 } else {
389 /* timed out, go back to init state */
390 state = INIT_SELECTING;
391 timeout = now;
392 packet_num = 0;
393 change_mode(LISTEN_RAW);
394 }
395 break;
396 case BOUND:
397 /* Lease is starting to run out, time to enter renewing state */
398 state = RENEWING;
399 change_mode(LISTEN_KERNEL);
400 DEBUG(LOG_INFO, "Entering renew state");
401 /* fall right through */
402 case RENEWING:
403 /* Either set a new T1, or enter REBINDING state */
404 if ((t2 - t1) <= (lease / 14400 + 1)) {
405 /* timed out, enter rebinding state */
406 state = REBINDING;
407 timeout = now + (t2 - t1);
408 DEBUG(LOG_INFO, "Entering rebinding state");
409 } else {
410 /* send a request packet */
411 send_renew(xid, server_addr, requested_ip); /* unicast */
412
413 t1 = (t2 - t1) / 2 + t1;
414 timeout = t1 + start;
415 }
416 break;
417 case REBINDING:
418 /* Either set a new T2, or enter INIT state */
419 if ((lease - t2) <= (lease / 14400 + 1)) {
420 /* timed out, enter init state */
421 state = INIT_SELECTING;
422 LOG(LOG_INFO, "Lease lost, entering init state");
423 run_script(NULL, "deconfig");
424 timeout = now;
425 packet_num = 0;
426 change_mode(LISTEN_RAW);
427 } else {
428 /* send a request packet */
429 send_renew(xid, 0, requested_ip); /* broadcast */
430
431 t2 = (lease - t2) / 2 + t2;
432 timeout = t2 + start;
433 }
434 break;
435 case RELEASED:
436 /* yah, I know, *you* say it would never happen */
437 timeout = 0x7fffffff;
438 break;
439 }
440 } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {
441 /* a packet is ready, read it */
442
443 if (listen_mode == LISTEN_KERNEL)
444 len = get_packet(&packet, fd);
445 else len = get_raw_packet(&packet, fd);
446
447 if (len == -1 && errno != EINTR) {
448 DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
449 change_mode(listen_mode); /* just close and reopen */
450 }
451 if (len < 0) continue;
452
453 if (packet.xid != xid) {
454 DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
455 (unsigned long) packet.xid, xid);
456 continue;
457 }
458
459 if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
460 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
461 continue;
462 }
463
464 switch (state) {
465 case INIT_SELECTING:
466 /* Must be a DHCPOFFER to one of our xid's */
467 if (*message == DHCPOFFER) {
468 if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
469 memcpy(&server_addr, temp, 4);
470 xid = packet.xid;
471 requested_ip = packet.yiaddr;
472
473 /* enter requesting state */
474 state = REQUESTING;
475 timeout = now;
476 packet_num = 0;
477 } else {
478 DEBUG(LOG_ERR, "No server ID in message");
479 }
480 }
481 break;
482 case RENEW_REQUESTED:
483 case REQUESTING:
484 case RENEWING:
485 case REBINDING:
486 if (*message == DHCPACK) {
487 if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
488 LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
489 lease = 60 * 60;
490 } else {
491 memcpy(&lease, temp, 4);
492 lease = ntohl(lease);
493 }
494
495 /* enter bound state */
496 t1 = lease / 2;
497
498 /* little fixed point for n * .875 */
499 t2 = (lease * 0x7) >> 3;
500 temp_addr.s_addr = packet.yiaddr;
501 LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
502 inet_ntoa(temp_addr), lease);
503 start = now;
504 timeout = t1 + start;
505 requested_ip = packet.yiaddr;
506 run_script(&packet,
507 ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
508
509 state = BOUND;
510 change_mode(LISTEN_NONE);
511 if (client_config.quit_after_lease)
512 exit_client(0);
513 if (!client_config.foreground)
514 background();
515
516 } else if (*message == DHCPNAK) {
517 /* return to init state */
518 LOG(LOG_INFO, "Received DHCP NAK");
519 run_script(&packet, "nak");
520 if (state != REQUESTING)
521 run_script(NULL, "deconfig");
522 state = INIT_SELECTING;
523 timeout = now;
524 requested_ip = 0;
525 packet_num = 0;
526 change_mode(LISTEN_RAW);
527 sleep(3); /* avoid excessive network traffic */
528 }
529 break;
530 /* case BOUND, RELEASED: - ignore all packets */
531 }
532 } else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
533 if (read(signal_pipe[0], &sig, sizeof(signal)) < 0) {
534 DEBUG(LOG_ERR, "Could not read signal: %s",
535 strerror(errno));
536 continue; /* probably just EINTR */
537 }
538 switch (sig) {
539 case SIGUSR1:
540 perform_renew();
541 break;
542 case SIGUSR2:
543 perform_release();
544 break;
545 case SIGTERM:
546 LOG(LOG_INFO, "Received SIGTERM");
547 exit_client(0);
548 }
549 } else if (retval == -1 && errno == EINTR) {
550 /* a signal was caught */
551 } else {
552 /* An error occured */
553 DEBUG(LOG_ERR, "Error on select");
554 }
555
556 }
557 return 0;
558}
559
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
new file mode 100644
index 000000000..52157f5c8
--- /dev/null
+++ b/networking/udhcp/dhcpc.h
@@ -0,0 +1,34 @@
1/* dhcpc.h */
2#ifndef _DHCPC_H
3#define _DHCPC_H
4
5#include "libbb_udhcp.h"
6
7#define INIT_SELECTING 0
8#define REQUESTING 1
9#define BOUND 2
10#define RENEWING 3
11#define REBINDING 4
12#define INIT_REBOOT 5
13#define RENEW_REQUESTED 6
14#define RELEASED 7
15
16
17struct client_config_t {
18 char foreground; /* Do not fork */
19 char quit_after_lease; /* Quit after obtaining lease */
20 char abort_if_no_lease; /* Abort if no lease */
21 char background_if_no_lease; /* Fork to background if no lease */
22 char *interface; /* The name of the interface to use */
23 char *pidfile; /* Optionally store the process ID */
24 char *script; /* User script to run at dhcp events */
25 unsigned char *clientid; /* Optional client id to use */
26 unsigned char *hostname; /* Optional hostname to use */
27 int ifindex; /* Index number of the interface to use */
28 unsigned char arp[6]; /* Our arp address */
29};
30
31extern struct client_config_t client_config;
32
33
34#endif
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
new file mode 100644
index 000000000..6c16dfeb0
--- /dev/null
+++ b/networking/udhcp/dhcpd.c
@@ -0,0 +1,287 @@
1/* dhcpd.c
2 *
3 * udhcp Server
4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
5 * Chris Trew <ctrew@moreton.com.au>
6 *
7 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
27#include <sys/wait.h>
28#include <sys/stat.h>
29#include <arpa/inet.h>
30#include <netdb.h>
31#include <netinet/in.h>
32#include <stdio.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <unistd.h>
36#include <signal.h>
37#include <errno.h>
38#include <sys/ioctl.h>
39#include <time.h>
40#include <sys/time.h>
41
42#include "debug.h"
43#include "dhcpd.h"
44#include "arpping.h"
45#include "socket.h"
46#include "options.h"
47#include "files.h"
48#include "leases.h"
49#include "packet.h"
50#include "serverpacket.h"
51#include "pidfile.h"
52
53
54/* globals */
55struct dhcpOfferedAddr *leases;
56struct server_config_t server_config;
57static int signal_pipe[2];
58
59/* Exit and cleanup */
60static void exit_server(int retval)
61{
62 pidfile_delete(server_config.pidfile);
63 CLOSE_LOG();
64 exit(retval);
65}
66
67
68/* Signal handler */
69static void signal_handler(int sig)
70{
71 if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
72 LOG(LOG_ERR, "Could not send signal: %s",
73 strerror(errno));
74 }
75}
76
77
78#ifdef COMBINED_BINARY
79int udhcpd_main(int argc, char *argv[])
80#else
81int main(int argc, char *argv[])
82#endif
83{
84 fd_set rfds;
85 struct timeval tv;
86 int server_socket = -1;
87 int bytes, retval;
88 struct dhcpMessage packet;
89 unsigned char *state;
90 unsigned char *server_id, *requested;
91 u_int32_t server_id_align, requested_align;
92 unsigned long timeout_end;
93 struct option_set *option;
94 struct dhcpOfferedAddr *lease;
95 int pid_fd;
96 int max_sock;
97 int sig;
98
99 OPEN_LOG("udhcpd");
100 LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);
101
102 memset(&server_config, 0, sizeof(struct server_config_t));
103
104 if (argc < 2)
105 read_config(DHCPD_CONF_FILE);
106 else read_config(argv[1]);
107
108 pid_fd = pidfile_acquire(server_config.pidfile);
109 pidfile_write_release(pid_fd);
110
111 if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
112 memcpy(&server_config.lease, option->data + 2, 4);
113 server_config.lease = ntohl(server_config.lease);
114 }
115 else server_config.lease = LEASE_TIME;
116
117 leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
118 memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
119 read_leases(server_config.lease_file);
120
121 if (read_interface(server_config.interface, &server_config.ifindex,
122 &server_config.server, server_config.arp) < 0)
123 exit_server(1);
124
125#ifndef DEBUGGING
126 pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */
127 if (daemon(0, 0) == -1) {
128 perror("fork");
129 exit_server(1);
130 }
131 pidfile_write_release(pid_fd);
132#endif
133
134
135 socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
136 signal(SIGUSR1, signal_handler);
137 signal(SIGTERM, signal_handler);
138
139 timeout_end = time(0) + server_config.auto_time;
140 while(1) { /* loop until universe collapses */
141
142 if (server_socket < 0)
143 if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
144 LOG(LOG_ERR, "FATAL: couldn't create server socket, %s", strerror(errno));
145 exit_server(0);
146 }
147
148 FD_ZERO(&rfds);
149 FD_SET(server_socket, &rfds);
150 FD_SET(signal_pipe[0], &rfds);
151 if (server_config.auto_time) {
152 tv.tv_sec = timeout_end - time(0);
153 tv.tv_usec = 0;
154 }
155 if (!server_config.auto_time || tv.tv_sec > 0) {
156 max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
157 retval = select(max_sock + 1, &rfds, NULL, NULL,
158 server_config.auto_time ? &tv : NULL);
159 } else retval = 0; /* If we already timed out, fall through */
160
161 if (retval == 0) {
162 write_leases();
163 timeout_end = time(0) + server_config.auto_time;
164 continue;
165 } else if (retval < 0 && errno != EINTR) {
166 DEBUG(LOG_INFO, "error on select");
167 continue;
168 }
169
170 if (FD_ISSET(signal_pipe[0], &rfds)) {
171 if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
172 continue; /* probably just EINTR */
173 switch (sig) {
174 case SIGUSR1:
175 LOG(LOG_INFO, "Received a SIGUSR1");
176 write_leases();
177 /* why not just reset the timeout, eh */
178 timeout_end = time(0) + server_config.auto_time;
179 continue;
180 case SIGTERM:
181 LOG(LOG_INFO, "Received a SIGTERM");
182 exit_server(0);
183 }
184 }
185
186 if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
187 if (bytes == -1 && errno != EINTR) {
188 DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
189 close(server_socket);
190 server_socket = -1;
191 }
192 continue;
193 }
194
195 if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
196 DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
197 continue;
198 }
199
200 /* ADDME: look for a static lease */
201 lease = find_lease_by_chaddr(packet.chaddr);
202 switch (state[0]) {
203 case DHCPDISCOVER:
204 DEBUG(LOG_INFO,"received DISCOVER");
205
206 if (sendOffer(&packet) < 0) {
207 LOG(LOG_ERR, "send OFFER failed");
208 }
209 break;
210 case DHCPREQUEST:
211 DEBUG(LOG_INFO, "received REQUEST");
212
213 requested = get_option(&packet, DHCP_REQUESTED_IP);
214 server_id = get_option(&packet, DHCP_SERVER_ID);
215
216 if (requested) memcpy(&requested_align, requested, 4);
217 if (server_id) memcpy(&server_id_align, server_id, 4);
218
219 if (lease) { /*ADDME: or static lease */
220 if (server_id) {
221 /* SELECTING State */
222 DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
223 if (server_id_align == server_config.server && requested &&
224 requested_align == lease->yiaddr) {
225 sendACK(&packet, lease->yiaddr);
226 }
227 } else {
228 if (requested) {
229 /* INIT-REBOOT State */
230 if (lease->yiaddr == requested_align)
231 sendACK(&packet, lease->yiaddr);
232 else sendNAK(&packet);
233 } else {
234 /* RENEWING or REBINDING State */
235 if (lease->yiaddr == packet.ciaddr)
236 sendACK(&packet, lease->yiaddr);
237 else {
238 /* don't know what to do!!!! */
239 sendNAK(&packet);
240 }
241 }
242 }
243
244 /* what to do if we have no record of the client */
245 } else if (server_id) {
246 /* SELECTING State */
247
248 } else if (requested) {
249 /* INIT-REBOOT State */
250 if ((lease = find_lease_by_yiaddr(requested_align))) {
251 if (lease_expired(lease)) {
252 /* probably best if we drop this lease */
253 memset(lease->chaddr, 0, 16);
254 /* make some contention for this address */
255 } else sendNAK(&packet);
256 } else if (requested_align < server_config.start ||
257 requested_align > server_config.end) {
258 sendNAK(&packet);
259 } /* else remain silent */
260
261 } else {
262 /* RENEWING or REBINDING State */
263 }
264 break;
265 case DHCPDECLINE:
266 DEBUG(LOG_INFO,"received DECLINE");
267 if (lease) {
268 memset(lease->chaddr, 0, 16);
269 lease->expires = time(0) + server_config.decline_time;
270 }
271 break;
272 case DHCPRELEASE:
273 DEBUG(LOG_INFO,"received RELEASE");
274 if (lease) lease->expires = time(0);
275 break;
276 case DHCPINFORM:
277 DEBUG(LOG_INFO,"received INFORM");
278 send_inform(&packet);
279 break;
280 default:
281 LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
282 }
283 }
284
285 return 0;
286}
287
diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h
new file mode 100644
index 000000000..2971e19db
--- /dev/null
+++ b/networking/udhcp/dhcpd.h
@@ -0,0 +1,131 @@
1/* dhcpd.h */
2#ifndef _DHCPD_H
3#define _DHCPD_H
4
5#include <netinet/ip.h>
6#include <netinet/udp.h>
7
8#include "libbb_udhcp.h"
9#include "leases.h"
10
11/************************************/
12/* Defaults _you_ may want to tweak */
13/************************************/
14
15/* the period of time the client is allowed to use that address */
16#define LEASE_TIME (60*60*24*10) /* 10 days of seconds */
17
18/* where to find the DHCP server configuration file */
19#define DHCPD_CONF_FILE "/etc/udhcpd.conf"
20
21/*****************************************************************/
22/* Do not modify below here unless you know what you are doing!! */
23/*****************************************************************/
24
25/* DHCP protocol -- see RFC 2131 */
26#define SERVER_PORT 67
27#define CLIENT_PORT 68
28
29#define DHCP_MAGIC 0x63825363
30
31/* DHCP option codes (partial list) */
32#define DHCP_PADDING 0x00
33#define DHCP_SUBNET 0x01
34#define DHCP_TIME_OFFSET 0x02
35#define DHCP_ROUTER 0x03
36#define DHCP_TIME_SERVER 0x04
37#define DHCP_NAME_SERVER 0x05
38#define DHCP_DNS_SERVER 0x06
39#define DHCP_LOG_SERVER 0x07
40#define DHCP_COOKIE_SERVER 0x08
41#define DHCP_LPR_SERVER 0x09
42#define DHCP_HOST_NAME 0x0c
43#define DHCP_BOOT_SIZE 0x0d
44#define DHCP_DOMAIN_NAME 0x0f
45#define DHCP_SWAP_SERVER 0x10
46#define DHCP_ROOT_PATH 0x11
47#define DHCP_IP_TTL 0x17
48#define DHCP_MTU 0x1a
49#define DHCP_BROADCAST 0x1c
50#define DHCP_NTP_SERVER 0x2a
51#define DHCP_WINS_SERVER 0x2c
52#define DHCP_REQUESTED_IP 0x32
53#define DHCP_LEASE_TIME 0x33
54#define DHCP_OPTION_OVER 0x34
55#define DHCP_MESSAGE_TYPE 0x35
56#define DHCP_SERVER_ID 0x36
57#define DHCP_PARAM_REQ 0x37
58#define DHCP_MESSAGE 0x38
59#define DHCP_MAX_SIZE 0x39
60#define DHCP_T1 0x3a
61#define DHCP_T2 0x3b
62#define DHCP_VENDOR 0x3c
63#define DHCP_CLIENT_ID 0x3d
64
65#define DHCP_END 0xFF
66
67
68#define BOOTREQUEST 1
69#define BOOTREPLY 2
70
71#define ETH_10MB 1
72#define ETH_10MB_LEN 6
73
74#define DHCPDISCOVER 1
75#define DHCPOFFER 2
76#define DHCPREQUEST 3
77#define DHCPDECLINE 4
78#define DHCPACK 5
79#define DHCPNAK 6
80#define DHCPRELEASE 7
81#define DHCPINFORM 8
82
83#define BROADCAST_FLAG 0x8000
84
85#define OPTION_FIELD 0
86#define FILE_FIELD 1
87#define SNAME_FIELD 2
88
89/* miscellaneous defines */
90#define MAC_BCAST_ADDR (unsigned char *) "\xff\xff\xff\xff\xff\xff"
91#define OPT_CODE 0
92#define OPT_LEN 1
93#define OPT_DATA 2
94
95struct option_set {
96 unsigned char *data;
97 struct option_set *next;
98};
99
100struct server_config_t {
101 u_int32_t server; /* Our IP, in network order */
102 u_int32_t start; /* Start address of leases, network order */
103 u_int32_t end; /* End of leases, network order */
104 struct option_set *options; /* List of DHCP options loaded from the config file */
105 char *interface; /* The name of the interface to use */
106 int ifindex; /* Index number of the interface to use */
107 unsigned char arp[6]; /* Our arp address */
108 unsigned long lease; /* lease time in seconds (host order) */
109 unsigned long max_leases; /* maximum number of leases (including reserved address) */
110 char remaining; /* should the lease file be interpreted as lease time remaining, or
111 * as the time the lease expires */
112 unsigned long auto_time; /* how long should udhcpd wait before writing a config file.
113 * if this is zero, it will only write one on SIGUSR1 */
114 unsigned long decline_time; /* how long an address is reserved if a client returns a
115 * decline message */
116 unsigned long conflict_time; /* how long an arp conflict offender is leased for */
117 unsigned long offer_time; /* how long an offered address is reserved */
118 unsigned long min_lease; /* minimum lease a client can request*/
119 char *lease_file;
120 char *pidfile;
121 char *notify_file; /* What to run whenever leases are written */
122 u_int32_t siaddr; /* next server bootp option */
123 char *sname; /* bootp server name */
124 char *boot_file; /* bootp boot file option */
125};
126
127extern struct server_config_t server_config;
128extern struct dhcpOfferedAddr *leases;
129
130
131#endif
diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c
new file mode 100644
index 000000000..2b19d9768
--- /dev/null
+++ b/networking/udhcp/dumpleases.c
@@ -0,0 +1,112 @@
1#include <fcntl.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <sys/wait.h>
6#include <sys/stat.h>
7#include <arpa/inet.h>
8#include <netdb.h>
9#include <netinet/in.h>
10#include <stdio.h>
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <unistd.h>
14#include <syslog.h>
15#include <signal.h>
16#include <errno.h>
17#include <getopt.h>
18#include <time.h>
19
20#include "libbb_udhcp.h"
21
22#define REMAINING 0
23#define ABSOLUTE 1
24
25struct lease_t {
26 unsigned char chaddr[16];
27 u_int32_t yiaddr;
28 u_int32_t expires;
29};
30
31#ifdef BB_VER
32int dumpleases_main(int argc, char *argv[])
33#else
34int main(int argc, char *argv[])
35#endif
36{
37 FILE *fp;
38 int i, c, mode = REMAINING;
39 long expires;
40 char file[255] = "/var/lib/misc/udhcpd.leases";
41 struct lease_t lease;
42 struct in_addr addr;
43
44 static struct option options[] = {
45 {"absolute", 0, 0, 'a'},
46 {"remaining", 0, 0, 'r'},
47 {"file", 1, 0, 'f'},
48 {"help", 0, 0, 'h'},
49 {0, 0, 0, 0}
50 };
51
52 while (1) {
53 int option_index = 0;
54 c = getopt_long(argc, argv, "arf:h", options, &option_index);
55 if (c == -1) break;
56
57 switch (c) {
58 case 'a': mode = ABSOLUTE; break;
59 case 'r': mode = REMAINING; break;
60 case 'f':
61 strncpy(file, optarg, 255);
62 file[254] = '\0';
63 break;
64 case 'h':
65 printf("Usage: dumpleases -f <file> -[r|a]\n\n");
66 printf(" -f, --file=FILENAME Leases file to load\n");
67 printf(" -r, --remaining Interepret lease times as time remaing\n");
68 printf(" -a, --absolute Interepret lease times as expire time\n");
69 break;
70 }
71 }
72
73 if (!(fp = fopen(file, "r"))) {
74 perror("could not open input file");
75 return 0;
76 }
77
78 printf("Mac Address IP-Address Expires %s\n", mode == REMAINING ? "in" : "at");
79 /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
80 while (fread(&lease, sizeof(lease), 1, fp)) {
81
82 for (i = 0; i < 6; i++) {
83 printf("%02x", lease.chaddr[i]);
84 if (i != 5) printf(":");
85 }
86 addr.s_addr = lease.yiaddr;
87 printf(" %-15s", inet_ntoa(addr));
88 expires = ntohl(lease.expires);
89 printf(" ");
90 if (mode == REMAINING) {
91 if (!expires) printf("expired\n");
92 else {
93 if (expires > 60*60*24) {
94 printf("%ld days, ", expires / (60*60*24));
95 expires %= 60*60*24;
96 }
97 if (expires > 60*60) {
98 printf("%ld hours, ", expires / (60*60));
99 expires %= 60*60;
100 }
101 if (expires > 60) {
102 printf("%ld minutes, ", expires / 60);
103 expires %= 60;
104 }
105 printf("%ld seconds\n", expires);
106 }
107 } else printf("%s", ctime(&expires));
108 }
109 fclose(fp);
110
111 return 0;
112}
diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c
new file mode 100644
index 000000000..842e0f2db
--- /dev/null
+++ b/networking/udhcp/files.c
@@ -0,0 +1,284 @@
1/*
2 * files.c -- DHCP server file manipulation *
3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
4 */
5
6#include <stdio.h>
7#include <sys/socket.h>
8#include <arpa/inet.h>
9#include <string.h>
10#include <stdlib.h>
11#include <time.h>
12#include <ctype.h>
13#include <netdb.h>
14
15#include "debug.h"
16#include "dhcpd.h"
17#include "files.h"
18#include "options.h"
19#include "leases.h"
20
21/* on these functions, make sure you datatype matches */
22static int read_ip(char *line, void *arg)
23{
24 struct in_addr *addr = arg;
25 struct hostent *host;
26 int retval = 1;
27
28 if (!inet_aton(line, addr)) {
29 if ((host = gethostbyname(line)))
30 addr->s_addr = *((unsigned long *) host->h_addr_list[0]);
31 else retval = 0;
32 }
33 return retval;
34}
35
36
37static int read_str(char *line, void *arg)
38{
39 char **dest = arg;
40
41 if (*dest) free(*dest);
42 *dest = strdup(line);
43
44 return 1;
45}
46
47
48static int read_u32(char *line, void *arg)
49{
50 u_int32_t *dest = arg;
51 char *endptr;
52 *dest = strtoul(line, &endptr, 0);
53 return endptr[0] == '\0';
54}
55
56
57static int read_yn(char *line, void *arg)
58{
59 char *dest = arg;
60 int retval = 1;
61
62 if (!strcasecmp("yes", line))
63 *dest = 1;
64 else if (!strcasecmp("no", line))
65 *dest = 0;
66 else retval = 0;
67
68 return retval;
69}
70
71
72/* read a dhcp option and add it to opt_list */
73static int read_opt(char *line, void *arg)
74{
75 struct option_set **opt_list = arg;
76 char *opt, *val, *endptr;
77 struct dhcp_option *option = NULL;
78 int retval = 0, length = 0;
79 char buffer[255];
80 u_int16_t result_u16;
81 u_int32_t result_u32;
82 int i;
83
84 if (!(opt = strtok(line, " \t="))) return 0;
85
86 for (i = 0; options[i].code; i++)
87 if (!strcmp(options[i].name, opt))
88 option = &(options[i]);
89
90 if (!option) return 0;
91
92 do {
93 val = strtok(NULL, ", \t");
94 if (val) {
95 length = option_lengths[option->flags & TYPE_MASK];
96 retval = 0;
97 switch (option->flags & TYPE_MASK) {
98 case OPTION_IP:
99 retval = read_ip(val, buffer);
100 break;
101 case OPTION_IP_PAIR:
102 retval = read_ip(val, buffer);
103 if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
104 if (retval) retval = read_ip(val, buffer + 4);
105 break;
106 case OPTION_STRING:
107 length = strlen(val);
108 if (length > 0) {
109 if (length > 254) length = 254;
110 memcpy(buffer, val, length);
111 retval = 1;
112 }
113 break;
114 case OPTION_BOOLEAN:
115 retval = read_yn(val, buffer);
116 break;
117 case OPTION_U8:
118 buffer[0] = strtoul(val, &endptr, 0);
119 retval = (endptr[0] == '\0');
120 break;
121 case OPTION_U16:
122 result_u16 = htons(strtoul(val, &endptr, 0));
123 memcpy(buffer, &result_u16, 2);
124 retval = (endptr[0] == '\0');
125 break;
126 case OPTION_S16:
127 result_u16 = htons(strtol(val, &endptr, 0));
128 memcpy(buffer, &result_u16, 2);
129 retval = (endptr[0] == '\0');
130 break;
131 case OPTION_U32:
132 result_u32 = htonl(strtoul(val, &endptr, 0));
133 memcpy(buffer, &result_u32, 4);
134 retval = (endptr[0] == '\0');
135 break;
136 case OPTION_S32:
137 result_u32 = htonl(strtol(val, &endptr, 0));
138 memcpy(buffer, &result_u32, 4);
139 retval = (endptr[0] == '\0');
140 break;
141 default:
142 break;
143 }
144 if (retval)
145 attach_option(opt_list, option, buffer, length);
146 };
147 } while (val && retval && option->flags & OPTION_LIST);
148 return retval;
149}
150
151
152static struct config_keyword keywords[] = {
153 /* keyword[14] handler variable address default[20] */
154 {"start", read_ip, &(server_config.start), "192.168.0.20"},
155 {"end", read_ip, &(server_config.end), "192.168.0.254"},
156 {"interface", read_str, &(server_config.interface), "eth0"},
157 {"option", read_opt, &(server_config.options), ""},
158 {"opt", read_opt, &(server_config.options), ""},
159 {"max_leases", read_u32, &(server_config.max_leases), "254"},
160 {"remaining", read_yn, &(server_config.remaining), "yes"},
161 {"auto_time", read_u32, &(server_config.auto_time), "7200"},
162 {"decline_time",read_u32, &(server_config.decline_time),"3600"},
163 {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},
164 {"offer_time", read_u32, &(server_config.offer_time), "60"},
165 {"min_lease", read_u32, &(server_config.min_lease), "60"},
166 {"lease_file", read_str, &(server_config.lease_file), "/var/lib/misc/udhcpd.leases"},
167 {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},
168 {"notify_file", read_str, &(server_config.notify_file), ""},
169 {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"},
170 {"sname", read_str, &(server_config.sname), ""},
171 {"boot_file", read_str, &(server_config.boot_file), ""},
172 /*ADDME: static lease */
173 {"", NULL, NULL, ""}
174};
175
176
177int read_config(char *file)
178{
179 FILE *in;
180 char buffer[80], orig[80], *token, *line;
181 int i;
182
183 for (i = 0; strlen(keywords[i].keyword); i++)
184 if (strlen(keywords[i].def))
185 keywords[i].handler(keywords[i].def, keywords[i].var);
186
187 if (!(in = fopen(file, "r"))) {
188 LOG(LOG_ERR, "unable to open config file: %s", file);
189 return 0;
190 }
191
192 while (fgets(buffer, 80, in)) {
193 if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
194 strncpy(orig, buffer, 80);
195 if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';
196 token = buffer + strspn(buffer, " \t");
197 if (*token == '\0') continue;
198 line = token + strcspn(token, " \t=");
199 if (*line == '\0') continue;
200 *line = '\0';
201 line++;
202
203 /* eat leading whitespace */
204 line = line + strspn(line, " \t=");
205 /* eat trailing whitespace */
206 for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--);
207 line[i] = '\0';
208
209 for (i = 0; strlen(keywords[i].keyword); i++)
210 if (!strcasecmp(token, keywords[i].keyword))
211 if (!keywords[i].handler(line, keywords[i].var)) {
212 LOG(LOG_ERR, "unable to parse '%s'", orig);
213 /* reset back to the default value */
214 keywords[i].handler(keywords[i].def, keywords[i].var);
215 }
216 }
217 fclose(in);
218 return 1;
219}
220
221
222void write_leases(void)
223{
224 FILE *fp;
225 unsigned int i;
226 char buf[255];
227 time_t curr = time(0);
228 unsigned long lease_time;
229
230 if (!(fp = fopen(server_config.lease_file, "w"))) {
231 LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
232 return;
233 }
234
235 for (i = 0; i < server_config.max_leases; i++) {
236 if (leases[i].yiaddr != 0) {
237 if (server_config.remaining) {
238 if (lease_expired(&(leases[i])))
239 lease_time = 0;
240 else lease_time = leases[i].expires - curr;
241 } else lease_time = leases[i].expires;
242 lease_time = htonl(lease_time);
243 fwrite(leases[i].chaddr, 16, 1, fp);
244 fwrite(&(leases[i].yiaddr), 4, 1, fp);
245 fwrite(&lease_time, 4, 1, fp);
246 }
247 }
248 fclose(fp);
249
250 if (server_config.notify_file) {
251 sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file);
252 system(buf);
253 }
254}
255
256
257void read_leases(char *file)
258{
259 FILE *fp;
260 unsigned int i = 0;
261 struct dhcpOfferedAddr lease;
262
263 if (!(fp = fopen(file, "r"))) {
264 LOG(LOG_ERR, "Unable to open %s for reading", file);
265 return;
266 }
267
268 while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
269 /* ADDME: is it a static lease */
270 if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {
271 lease.expires = ntohl(lease.expires);
272 if (!server_config.remaining) lease.expires -= time(0);
273 if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
274 LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
275 break;
276 }
277 i++;
278 }
279 }
280 DEBUG(LOG_INFO, "Read %d leases", i);
281 fclose(fp);
282}
283
284
diff --git a/networking/udhcp/files.h b/networking/udhcp/files.h
new file mode 100644
index 000000000..1f2638fe9
--- /dev/null
+++ b/networking/udhcp/files.h
@@ -0,0 +1,17 @@
1/* files.h */
2#ifndef _FILES_H
3#define _FILES_H
4
5struct config_keyword {
6 char keyword[14];
7 int (*handler)(char *line, void *var);
8 void *var;
9 char def[30];
10};
11
12
13int read_config(char *file);
14void write_leases(void);
15void read_leases(char *file);
16
17#endif
diff --git a/networking/udhcp/frontend.c b/networking/udhcp/frontend.c
new file mode 100644
index 000000000..de5779508
--- /dev/null
+++ b/networking/udhcp/frontend.c
@@ -0,0 +1,16 @@
1#include <string.h>
2
3extern int udhcpd_main(int argc, char *argv[]);
4extern int udhcpc_main(int argc, char *argv[]);
5
6int main(int argc, char *argv[])
7{
8 int ret = 0;
9 char *base = strrchr(argv[0], '/');
10
11 if (strstr(base ? (base + 1) : argv[0], "dhcpd"))
12 ret = udhcpd_main(argc, argv);
13 else ret = udhcpc_main(argc, argv);
14
15 return ret;
16}
diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c
new file mode 100644
index 000000000..7ade91d93
--- /dev/null
+++ b/networking/udhcp/leases.c
@@ -0,0 +1,151 @@
1/*
2 * leases.c -- tools to manage DHCP leases
3 * Russ Dill <Russ.Dill@asu.edu> July 2001
4 */
5
6#include <time.h>
7#include <string.h>
8#include <sys/socket.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11
12#include "debug.h"
13#include "dhcpd.h"
14#include "files.h"
15#include "options.h"
16#include "leases.h"
17#include "arpping.h"
18
19unsigned char blank_chaddr[] = {[0 ... 15] = 0};
20
21/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
22void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr)
23{
24 unsigned int i, j;
25
26 for (j = 0; j < 16 && !chaddr[j]; j++);
27
28 for (i = 0; i < server_config.max_leases; i++)
29 if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
30 (yiaddr && leases[i].yiaddr == yiaddr)) {
31 memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
32 }
33}
34
35
36/* add a lease into the table, clearing out any old ones */
37struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease)
38{
39 struct dhcpOfferedAddr *oldest;
40
41 /* clean out any old ones */
42 clear_lease(chaddr, yiaddr);
43
44 oldest = oldest_expired_lease();
45
46 if (oldest) {
47 memcpy(oldest->chaddr, chaddr, 16);
48 oldest->yiaddr = yiaddr;
49 oldest->expires = time(0) + lease;
50 }
51
52 return oldest;
53}
54
55
56/* true if a lease has expired */
57int lease_expired(struct dhcpOfferedAddr *lease)
58{
59 return (lease->expires < (unsigned long) time(0));
60}
61
62
63/* Find the oldest expired lease, NULL if there are no expired leases */
64struct dhcpOfferedAddr *oldest_expired_lease(void)
65{
66 struct dhcpOfferedAddr *oldest = NULL;
67 unsigned long oldest_lease = time(0);
68 unsigned int i;
69
70
71 for (i = 0; i < server_config.max_leases; i++)
72 if (oldest_lease > leases[i].expires) {
73 oldest_lease = leases[i].expires;
74 oldest = &(leases[i]);
75 }
76 return oldest;
77
78}
79
80
81/* Find the first lease that matches chaddr, NULL if no match */
82struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr)
83{
84 unsigned int i;
85
86 for (i = 0; i < server_config.max_leases; i++)
87 if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
88
89 return NULL;
90}
91
92
93/* Find the first lease that matches yiaddr, NULL is no match */
94struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr)
95{
96 unsigned int i;
97
98 for (i = 0; i < server_config.max_leases; i++)
99 if (leases[i].yiaddr == yiaddr) return &(leases[i]);
100
101 return NULL;
102}
103
104
105/* find an assignable address, it check_expired is true, we check all the expired leases as well.
106 * Maybe this should try expired leases by age... */
107u_int32_t find_address(int check_expired)
108{
109 u_int32_t addr, ret;
110 struct dhcpOfferedAddr *lease = NULL;
111
112 addr = ntohl(server_config.start); /* addr is in host order here */
113 for (;addr <= ntohl(server_config.end); addr++) {
114
115 /* ie, 192.168.55.0 */
116 if (!(addr & 0xFF)) continue;
117
118 /* ie, 192.168.55.255 */
119 if ((addr & 0xFF) == 0xFF) continue;
120
121 /* lease is not taken */
122 ret = htonl(addr);
123 if ((!(lease = find_lease_by_yiaddr(ret)) ||
124
125 /* or it expired and we are checking for expired leases */
126 (check_expired && lease_expired(lease))) &&
127
128 /* and it isn't on the network */
129 !check_ip(ret)) {
130 return ret;
131 break;
132 }
133 }
134 return 0;
135}
136
137
138/* check is an IP is taken, if it is, add it to the lease table */
139int check_ip(u_int32_t addr)
140{
141 struct in_addr temp;
142
143 if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
144 temp.s_addr = addr;
145 LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
146 inet_ntoa(temp), server_config.conflict_time);
147 add_lease(blank_chaddr, addr, server_config.conflict_time);
148 return 1;
149 } else return 0;
150}
151
diff --git a/networking/udhcp/leases.h b/networking/udhcp/leases.h
new file mode 100644
index 000000000..bc50f68de
--- /dev/null
+++ b/networking/udhcp/leases.h
@@ -0,0 +1,24 @@
1/* leases.h */
2#ifndef _LEASES_H
3#define _LEASES_H
4
5
6struct dhcpOfferedAddr {
7 u_int8_t chaddr[16];
8 u_int32_t yiaddr; /* network order */
9 u_int32_t expires; /* host order */
10};
11
12extern unsigned char blank_chaddr[];
13
14void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr);
15struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease);
16int lease_expired(struct dhcpOfferedAddr *lease);
17struct dhcpOfferedAddr *oldest_expired_lease(void);
18struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr);
19struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr);
20u_int32_t find_address(int check_expired);
21int check_ip(u_int32_t addr);
22
23
24#endif
diff --git a/networking/udhcp/libbb_udhcp.h b/networking/udhcp/libbb_udhcp.h
new file mode 100644
index 000000000..d3f72c65b
--- /dev/null
+++ b/networking/udhcp/libbb_udhcp.h
@@ -0,0 +1,29 @@
1/* libbb_udhcp.h - busybox compatability wrapper */
2
3#ifndef _LIBBB_UDHCP_H
4#define _LIBBB_UDHCP_H
5
6#ifdef BB_VER
7#include "libbb.h"
8
9#ifdef CONFIG_FEATURE_UDHCP_SYSLOG
10#define SYSLOG
11#endif
12
13#ifdef CONFIG_FEATURE_UDHCP_DEBUG
14#define DEBUG
15#endif
16
17#define COMBINED_BINARY
18#define VERSION "0.9.8-pre"
19
20#else /* ! BB_VER */
21
22#define TRUE 1
23#define FALSE 0
24
25#define xmalloc malloc
26
27#endif /* BB_VER */
28
29#endif /* _LIBBB_UDHCP_H */
diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c
new file mode 100644
index 000000000..58144728e
--- /dev/null
+++ b/networking/udhcp/options.c
@@ -0,0 +1,230 @@
1/*
2 * options.c -- DHCP server option packet tools
3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "debug.h"
11#include "dhcpd.h"
12#include "files.h"
13#include "options.h"
14#include "leases.h"
15
16
17/* supported options are easily added here */
18struct dhcp_option options[] = {
19 /* name[10] flags code */
20 {"subnet", OPTION_IP | OPTION_REQ, 0x01},
21 {"timezone", OPTION_S32, 0x02},
22 {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03},
23 {"timesvr", OPTION_IP | OPTION_LIST, 0x04},
24 {"namesvr", OPTION_IP | OPTION_LIST, 0x05},
25 {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06},
26 {"logsvr", OPTION_IP | OPTION_LIST, 0x07},
27 {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08},
28 {"lprsvr", OPTION_IP | OPTION_LIST, 0x09},
29 {"hostname", OPTION_STRING | OPTION_REQ, 0x0c},
30 {"bootsize", OPTION_U16, 0x0d},
31 {"domain", OPTION_STRING | OPTION_REQ, 0x0f},
32 {"swapsvr", OPTION_IP, 0x10},
33 {"rootpath", OPTION_STRING, 0x11},
34 {"ipttl", OPTION_U8, 0x17},
35 {"mtu", OPTION_U16, 0x1a},
36 {"broadcast", OPTION_IP | OPTION_REQ, 0x1c},
37 {"ntpsrv", OPTION_IP | OPTION_LIST, 0x2a},
38 {"wins", OPTION_IP | OPTION_LIST, 0x2c},
39 {"requestip", OPTION_IP, 0x32},
40 {"lease", OPTION_U32, 0x33},
41 {"dhcptype", OPTION_U8, 0x35},
42 {"serverid", OPTION_IP, 0x36},
43 {"message", OPTION_STRING, 0x38},
44 {"tftp", OPTION_STRING, 0x42},
45 {"bootfile", OPTION_STRING, 0x43},
46 {"", 0x00, 0x00}
47};
48
49/* Lengths of the different option types */
50int option_lengths[] = {
51 [OPTION_IP] = 4,
52 [OPTION_IP_PAIR] = 8,
53 [OPTION_BOOLEAN] = 1,
54 [OPTION_STRING] = 1,
55 [OPTION_U8] = 1,
56 [OPTION_U16] = 2,
57 [OPTION_S16] = 2,
58 [OPTION_U32] = 4,
59 [OPTION_S32] = 4
60};
61
62
63/* get an option with bounds checking (warning, not aligned). */
64unsigned char *get_option(struct dhcpMessage *packet, int code)
65{
66 int i, length;
67 unsigned char *optionptr;
68 int over = 0, done = 0, curr = OPTION_FIELD;
69
70 optionptr = packet->options;
71 i = 0;
72 length = 308;
73 while (!done) {
74 if (i >= length) {
75 LOG(LOG_WARNING, "bogus packet, option fields too long.");
76 return NULL;
77 }
78 if (optionptr[i + OPT_CODE] == code) {
79 if (i + 1 + optionptr[i + OPT_LEN] >= length) {
80 LOG(LOG_WARNING, "bogus packet, option fields too long.");
81 return NULL;
82 }
83 return optionptr + i + 2;
84 }
85 switch (optionptr[i + OPT_CODE]) {
86 case DHCP_PADDING:
87 i++;
88 break;
89 case DHCP_OPTION_OVER:
90 if (i + 1 + optionptr[i + OPT_LEN] >= length) {
91 LOG(LOG_WARNING, "bogus packet, option fields too long.");
92 return NULL;
93 }
94 over = optionptr[i + 3];
95 i += optionptr[OPT_LEN] + 2;
96 break;
97 case DHCP_END:
98 if (curr == OPTION_FIELD && over & FILE_FIELD) {
99 optionptr = packet->file;
100 i = 0;
101 length = 128;
102 curr = FILE_FIELD;
103 } else if (curr == FILE_FIELD && over & SNAME_FIELD) {
104 optionptr = packet->sname;
105 i = 0;
106 length = 64;
107 curr = SNAME_FIELD;
108 } else done = 1;
109 break;
110 default:
111 i += optionptr[OPT_LEN + i] + 2;
112 }
113 }
114 return NULL;
115}
116
117
118/* return the position of the 'end' option (no bounds checking) */
119int end_option(unsigned char *optionptr)
120{
121 int i = 0;
122
123 while (optionptr[i] != DHCP_END) {
124 if (optionptr[i] == DHCP_PADDING) i++;
125 else i += optionptr[i + OPT_LEN] + 2;
126 }
127 return i;
128}
129
130
131/* add an option string to the options (an option string contains an option code,
132 * length, then data) */
133int add_option_string(unsigned char *optionptr, unsigned char *string)
134{
135 int end = end_option(optionptr);
136
137 /* end position + string length + option code/length + end option */
138 if (end + string[OPT_LEN] + 2 + 1 >= 308) {
139 LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]);
140 return 0;
141 }
142 DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);
143 memcpy(optionptr + end, string, string[OPT_LEN] + 2);
144 optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
145 return string[OPT_LEN] + 2;
146}
147
148
149/* add a one to four byte option to a packet */
150int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data)
151{
152 char length = 0;
153 int i;
154 unsigned char option[2 + 4];
155 unsigned char *u8;
156 u_int16_t *u16;
157 u_int32_t *u32;
158 u_int32_t aligned;
159 u8 = (unsigned char *) &aligned;
160 u16 = (u_int16_t *) &aligned;
161 u32 = &aligned;
162
163 for (i = 0; options[i].code; i++)
164 if (options[i].code == code) {
165 length = option_lengths[options[i].flags & TYPE_MASK];
166 }
167
168 if (!length) {
169 DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
170 return 0;
171 }
172
173 option[OPT_CODE] = code;
174 option[OPT_LEN] = length;
175
176 switch (length) {
177 case 1: *u8 = data; break;
178 case 2: *u16 = data; break;
179 case 4: *u32 = data; break;
180 }
181 memcpy(option + 2, &aligned, length);
182 return add_option_string(optionptr, option);
183}
184
185
186/* find option 'code' in opt_list */
187struct option_set *find_option(struct option_set *opt_list, char code)
188{
189 while (opt_list && opt_list->data[OPT_CODE] < code)
190 opt_list = opt_list->next;
191
192 if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
193 else return NULL;
194}
195
196
197/* add an option to the opt_list */
198void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
199{
200 struct option_set *existing, *new, **curr;
201
202 /* add it to an existing option */
203 if ((existing = find_option(*opt_list, option->code))) {
204 DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
205 if (option->flags & OPTION_LIST) {
206 if (existing->data[OPT_LEN] + length <= 255) {
207 existing->data = realloc(existing->data,
208 existing->data[OPT_LEN] + length + 2);
209 memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
210 existing->data[OPT_LEN] += length;
211 } /* else, ignore the data, we could put this in a second option in the future */
212 } /* else, ignore the new data */
213 } else {
214 DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
215
216 /* make a new option */
217 new = malloc(sizeof(struct option_set));
218 new->data = malloc(length + 2);
219 new->data[OPT_CODE] = option->code;
220 new->data[OPT_LEN] = length;
221 memcpy(new->data + 2, buffer, length);
222
223 curr = opt_list;
224 while (*curr && (*curr)->data[OPT_CODE] < option->code)
225 curr = &(*curr)->next;
226
227 new->next = *curr;
228 *curr = new;
229 }
230}
diff --git a/networking/udhcp/options.h b/networking/udhcp/options.h
new file mode 100644
index 000000000..1fded2ef4
--- /dev/null
+++ b/networking/udhcp/options.h
@@ -0,0 +1,40 @@
1/* options.h */
2#ifndef _OPTIONS_H
3#define _OPTIONS_H
4
5#include "packet.h"
6
7#define TYPE_MASK 0x0F
8
9enum {
10 OPTION_IP=1,
11 OPTION_IP_PAIR,
12 OPTION_STRING,
13 OPTION_BOOLEAN,
14 OPTION_U8,
15 OPTION_U16,
16 OPTION_S16,
17 OPTION_U32,
18 OPTION_S32
19};
20
21#define OPTION_REQ 0x10 /* have the client request this option */
22#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
23
24struct dhcp_option {
25 char name[10];
26 char flags;
27 unsigned char code;
28};
29
30extern struct dhcp_option options[];
31extern int option_lengths[];
32
33unsigned char *get_option(struct dhcpMessage *packet, int code);
34int end_option(unsigned char *optionptr);
35int add_option_string(unsigned char *optionptr, unsigned char *string);
36int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data);
37struct option_set *find_option(struct option_set *opt_list, char code);
38void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length);
39
40#endif
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
new file mode 100644
index 000000000..d9f715971
--- /dev/null
+++ b/networking/udhcp/packet.c
@@ -0,0 +1,203 @@
1#include <unistd.h>
2#include <string.h>
3#include <netinet/in.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <features.h>
7#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
8#include <netpacket/packet.h>
9#include <net/ethernet.h>
10#else
11#include <asm/types.h>
12#include <linux/if_packet.h>
13#include <linux/if_ether.h>
14#endif
15#include <errno.h>
16
17#include "packet.h"
18#include "debug.h"
19#include "dhcpd.h"
20#include "options.h"
21
22
23void init_header(struct dhcpMessage *packet, char type)
24{
25 memset(packet, 0, sizeof(struct dhcpMessage));
26 switch (type) {
27 case DHCPDISCOVER:
28 case DHCPREQUEST:
29 case DHCPRELEASE:
30 case DHCPINFORM:
31 packet->op = BOOTREQUEST;
32 break;
33 case DHCPOFFER:
34 case DHCPACK:
35 case DHCPNAK:
36 packet->op = BOOTREPLY;
37 }
38 packet->htype = ETH_10MB;
39 packet->hlen = ETH_10MB_LEN;
40 packet->cookie = htonl(DHCP_MAGIC);
41 packet->options[0] = DHCP_END;
42 add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
43}
44
45
46/* read a packet from socket fd, return -1 on read error, -2 on packet error */
47int get_packet(struct dhcpMessage *packet, int fd)
48{
49 int bytes;
50 int i;
51 const char broken_vendors[][8] = {
52 "MSFT 98",
53 ""
54 };
55 char unsigned *vendor;
56
57 memset(packet, 0, sizeof(struct dhcpMessage));
58 bytes = read(fd, packet, sizeof(struct dhcpMessage));
59 if (bytes < 0) {
60 DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
61 return -1;
62 }
63
64 if (ntohl(packet->cookie) != DHCP_MAGIC) {
65 LOG(LOG_ERR, "received bogus message, ignoring");
66 return -2;
67 }
68 DEBUG(LOG_INFO, "Received a packet");
69
70 if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) {
71 for (i = 0; broken_vendors[i][0]; i++) {
72 if (vendor[OPT_LEN - 2] == (unsigned char) strlen(broken_vendors[i]) &&
73 !strncmp(vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
74 DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
75 broken_vendors[i]);
76 packet->flags |= htons(BROADCAST_FLAG);
77 }
78 }
79 }
80
81
82 return bytes;
83}
84
85
86u_int16_t checksum(void *addr, int count)
87{
88 /* Compute Internet Checksum for "count" bytes
89 * beginning at location "addr".
90 */
91 register int32_t sum = 0;
92 u_int16_t *source = (u_int16_t *) addr;
93
94 while (count > 1) {
95 /* This is the inner loop */
96 sum += *source++;
97 count -= 2;
98 }
99
100 /* Add left-over byte, if any */
101 if (count > 0) {
102 /* Make sure that the left-over byte is added correctly both
103 * with little and big endian hosts */
104 u_int16_t tmp = 0;
105 *(unsigned char *) (&tmp) = * (unsigned char *) source;
106 sum += tmp;
107 }
108 /* Fold 32-bit sum to 16 bits */
109 while (sum >> 16)
110 sum = (sum & 0xffff) + (sum >> 16);
111
112 return ~sum;
113}
114
115
116/* Constuct a ip/udp header for a packet, and specify the source and dest hardware address */
117int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
118 u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex)
119{
120 int fd;
121 int result;
122 struct sockaddr_ll dest;
123 struct udp_dhcp_packet packet;
124
125 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
126 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
127 return -1;
128 }
129
130 memset(&dest, 0, sizeof(dest));
131 memset(&packet, 0, sizeof(packet));
132
133 dest.sll_family = AF_PACKET;
134 dest.sll_protocol = htons(ETH_P_IP);
135 dest.sll_ifindex = ifindex;
136 dest.sll_halen = 6;
137 memcpy(dest.sll_addr, dest_arp, 6);
138 if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
139 DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
140 close(fd);
141 return -1;
142 }
143
144 packet.ip.protocol = IPPROTO_UDP;
145 packet.ip.saddr = source_ip;
146 packet.ip.daddr = dest_ip;
147 packet.udp.source = htons(source_port);
148 packet.udp.dest = htons(dest_port);
149 packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
150 packet.ip.tot_len = packet.udp.len;
151 memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
152 packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
153
154 packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
155 packet.ip.ihl = sizeof(packet.ip) >> 2;
156 packet.ip.version = IPVERSION;
157 packet.ip.ttl = IPDEFTTL;
158 packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
159
160 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
161 if (result <= 0) {
162 DEBUG(LOG_ERR, "write on socket failed: %s", strerror(errno));
163 }
164 close(fd);
165 return result;
166}
167
168
169/* Let the kernel do all the work for packet generation */
170int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
171 u_int32_t dest_ip, int dest_port)
172{
173 int n = 1;
174 int fd, result;
175 struct sockaddr_in client;
176
177 if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
178 return -1;
179
180 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
181 return -1;
182
183 memset(&client, 0, sizeof(client));
184 client.sin_family = AF_INET;
185 client.sin_port = htons(source_port);
186 client.sin_addr.s_addr = source_ip;
187
188 if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
189 return -1;
190
191 memset(&client, 0, sizeof(client));
192 client.sin_family = AF_INET;
193 client.sin_port = htons(dest_port);
194 client.sin_addr.s_addr = dest_ip;
195
196 if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
197 return -1;
198
199 result = write(fd, payload, sizeof(struct dhcpMessage));
200 close(fd);
201 return result;
202}
203
diff --git a/networking/udhcp/packet.h b/networking/udhcp/packet.h
new file mode 100644
index 000000000..1a263ef8b
--- /dev/null
+++ b/networking/udhcp/packet.h
@@ -0,0 +1,41 @@
1#ifndef _PACKET_H
2#define _PACKET_H
3
4#include <netinet/udp.h>
5#include <netinet/ip.h>
6
7struct dhcpMessage {
8 u_int8_t op;
9 u_int8_t htype;
10 u_int8_t hlen;
11 u_int8_t hops;
12 u_int32_t xid;
13 u_int16_t secs;
14 u_int16_t flags;
15 u_int32_t ciaddr;
16 u_int32_t yiaddr;
17 u_int32_t siaddr;
18 u_int32_t giaddr;
19 u_int8_t chaddr[16];
20 u_int8_t sname[64];
21 u_int8_t file[128];
22 u_int32_t cookie;
23 u_int8_t options[308]; /* 312 - cookie */
24};
25
26struct udp_dhcp_packet {
27 struct iphdr ip;
28 struct udphdr udp;
29 struct dhcpMessage data;
30};
31
32void init_header(struct dhcpMessage *packet, char type);
33int get_packet(struct dhcpMessage *packet, int fd);
34u_int16_t checksum(void *addr, int count);
35int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
36 u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex);
37int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
38 u_int32_t dest_ip, int dest_port);
39
40
41#endif
diff --git a/networking/udhcp/pidfile.c b/networking/udhcp/pidfile.c
new file mode 100644
index 000000000..246a64aa1
--- /dev/null
+++ b/networking/udhcp/pidfile.c
@@ -0,0 +1,69 @@
1/* pidfile.c
2 *
3 * Functions to assist in the writing and removing of pidfiles.
4 *
5 * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
29
30#include "debug.h"
31
32int pidfile_acquire(char *pidfile)
33{
34 int pid_fd;
35 if (pidfile == NULL) return -1;
36
37 pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644);
38 if (pid_fd < 0) {
39 LOG(LOG_ERR, "Unable to open pidfile %s: %s\n",
40 pidfile, strerror(errno));
41 } else {
42 lockf(pid_fd, F_LOCK, 0);
43 }
44
45 return pid_fd;
46}
47
48
49void pidfile_write_release(int pid_fd)
50{
51 FILE *out;
52
53 if (pid_fd < 0) return;
54
55 if ((out = fdopen(pid_fd, "w")) != NULL) {
56 fprintf(out, "%d\n", getpid());
57 fclose(out);
58 }
59 lockf(pid_fd, F_UNLCK, 0);
60 close(pid_fd);
61}
62
63
64void pidfile_delete(char *pidfile)
65{
66 if (pidfile) unlink(pidfile);
67}
68
69
diff --git a/networking/udhcp/pidfile.h b/networking/udhcp/pidfile.h
new file mode 100644
index 000000000..0e2b148a9
--- /dev/null
+++ b/networking/udhcp/pidfile.h
@@ -0,0 +1,26 @@
1/* pidfile.h
2 *
3 * Functions to assist in the writing and removing of pidfiles.
4 *
5 * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23int pidfile_acquire(char *pidfile);
24void pidfile_write_release(int pid_fd);
25void pidfile_delete(char *pidfile);
26
diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c
new file mode 100644
index 000000000..4ce23aafc
--- /dev/null
+++ b/networking/udhcp/script.c
@@ -0,0 +1,228 @@
1/* script.c
2 *
3 * Functions to call the DHCP client notification scripts
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <string.h>
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <sys/types.h>
30#include <sys/wait.h>
31#include <errno.h>
32
33#include "options.h"
34#include "dhcpd.h"
35#include "dhcpc.h"
36#include "packet.h"
37#include "options.h"
38#include "debug.h"
39
40/* get a rough idea of how long an option will be (rounding up...) */
41static int max_option_length[] = {
42 [OPTION_IP] = sizeof("255.255.255.255 "),
43 [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
44 [OPTION_STRING] = 1,
45 [OPTION_BOOLEAN] = sizeof("yes "),
46 [OPTION_U8] = sizeof("255 "),
47 [OPTION_U16] = sizeof("65535 "),
48 [OPTION_S16] = sizeof("-32768 "),
49 [OPTION_U32] = sizeof("4294967295 "),
50 [OPTION_S32] = sizeof("-2147483684 "),
51};
52
53
54static int upper_length(int length, struct dhcp_option *option)
55{
56 return max_option_length[option->flags & TYPE_MASK] *
57 (length / option_lengths[option->flags & TYPE_MASK]);
58}
59
60
61static int sprintip(char *dest, char *pre, unsigned char *ip) {
62 return sprintf(dest, "%s%d.%d.%d.%d ", pre, ip[0], ip[1], ip[2], ip[3]);
63}
64
65
66/* Fill dest with the text of option 'option'. */
67static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p)
68{
69 int type, optlen;
70 u_int16_t val_u16;
71 int16_t val_s16;
72 u_int32_t val_u32;
73 int32_t val_s32;
74 int len = option[OPT_LEN - 2];
75
76 dest += sprintf(dest, "%s=", type_p->name);
77
78 type = type_p->flags & TYPE_MASK;
79 optlen = option_lengths[type];
80 for(;;) {
81 switch (type) {
82 case OPTION_IP_PAIR:
83 dest += sprintip(dest, "", option);
84 *(dest++) = '/';
85 option += 4;
86 optlen = 4;
87 case OPTION_IP: /* Works regardless of host byte order. */
88 dest += sprintip(dest, "", option);
89 break;
90 case OPTION_BOOLEAN:
91 dest += sprintf(dest, *option ? "yes " : "no ");
92 break;
93 case OPTION_U8:
94 dest += sprintf(dest, "%u ", *option);
95 break;
96 case OPTION_U16:
97 memcpy(&val_u16, option, 2);
98 dest += sprintf(dest, "%u ", ntohs(val_u16));
99 break;
100 case OPTION_S16:
101 memcpy(&val_s16, option, 2);
102 dest += sprintf(dest, "%d ", ntohs(val_s16));
103 break;
104 case OPTION_U32:
105 memcpy(&val_u32, option, 4);
106 dest += sprintf(dest, "%lu ", (unsigned long) ntohl(val_u32));
107 break;
108 case OPTION_S32:
109 memcpy(&val_s32, option, 4);
110 dest += sprintf(dest, "%ld ", (long) ntohl(val_s32));
111 break;
112 case OPTION_STRING:
113 memcpy(dest, option, len);
114 dest[len] = '\0';
115 return; /* Short circuit this case */
116 }
117 option += optlen;
118 len -= optlen;
119 if (len <= 0) break;
120 }
121}
122
123
124static char *find_env(const char *prefix, char *defaultstr)
125{
126 extern char **environ;
127 char **ptr;
128 const int len = strlen(prefix);
129
130 for (ptr = environ; *ptr != NULL; ptr++) {
131 if (strncmp(prefix, *ptr, len) == 0)
132 return *ptr;
133 }
134 return defaultstr;
135}
136
137
138/* put all the paramaters into an environment */
139static char **fill_envp(struct dhcpMessage *packet)
140{
141 int num_options = 0;
142 int i, j;
143 char **envp;
144 unsigned char *temp;
145 char over = 0;
146
147 if (packet == NULL)
148 num_options = 0;
149 else {
150 for (i = 0; options[i].code; i++)
151 if (get_option(packet, options[i].code))
152 num_options++;
153 if (packet->siaddr) num_options++;
154 if ((temp = get_option(packet, DHCP_OPTION_OVER)))
155 over = *temp;
156 if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
157 if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
158 }
159
160 envp = xmalloc((num_options + 5) * sizeof(char *));
161 envp[0] = xmalloc(sizeof("interface=") + strlen(client_config.interface));
162 sprintf(envp[0], "interface=%s", client_config.interface);
163 envp[1] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");
164 envp[2] = find_env("HOME", "HOME=/");
165
166 if (packet == NULL) {
167 envp[3] = NULL;
168 return envp;
169 }
170
171 envp[3] = xmalloc(sizeof("ip=255.255.255.255"));
172 sprintip(envp[3], "ip=", (unsigned char *) &packet->yiaddr);
173 for (i = 0, j = 4; options[i].code; i++) {
174 if ((temp = get_option(packet, options[i].code))) {
175 envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], &options[i]) + strlen(options[i].name) + 2);
176 fill_options(envp[j], temp, &options[i]);
177 j++;
178 }
179 }
180 if (packet->siaddr) {
181 envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));
182 sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);
183 }
184 if (!(over & FILE_FIELD) && packet->file[0]) {
185 /* watch out for invalid packets */
186 packet->file[sizeof(packet->file) - 1] = '\0';
187 envp[j] = xmalloc(sizeof("boot_file=") + strlen(packet->file));
188 sprintf(envp[j++], "boot_file=%s", packet->file);
189 }
190 if (!(over & SNAME_FIELD) && packet->sname[0]) {
191 /* watch out for invalid packets */
192 packet->sname[sizeof(packet->sname) - 1] = '\0';
193 envp[j] = xmalloc(sizeof("sname=") + strlen(packet->sname));
194 sprintf(envp[j++], "sname=%s", packet->sname);
195 }
196 envp[j] = NULL;
197 return envp;
198}
199
200
201/* Call a script with a par file and env vars */
202void run_script(struct dhcpMessage *packet, const char *name)
203{
204 int pid;
205 char **envp;
206
207 if (client_config.script == NULL)
208 return;
209
210 /* call script */
211 pid = fork();
212 if (pid) {
213 waitpid(pid, NULL, 0);
214 return;
215 } else if (pid == 0) {
216 envp = fill_envp(packet);
217
218 /* close fd's? */
219
220 /* exec script */
221 DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
222 execle(client_config.script, client_config.script,
223 name, NULL, envp);
224 LOG(LOG_ERR, "script %s failed: %s",
225 client_config.script, strerror(errno));
226 exit(1);
227 }
228}
diff --git a/networking/udhcp/script.h b/networking/udhcp/script.h
new file mode 100644
index 000000000..87a20cc17
--- /dev/null
+++ b/networking/udhcp/script.h
@@ -0,0 +1,6 @@
1#ifndef _SCRIPT_H
2#define _SCRIPT_H
3
4void run_script(struct dhcpMessage *packet, const char *name);
5
6#endif
diff --git a/networking/udhcp/serverpacket.c b/networking/udhcp/serverpacket.c
new file mode 100644
index 000000000..e969c7af8
--- /dev/null
+++ b/networking/udhcp/serverpacket.c
@@ -0,0 +1,263 @@
1/* serverpacket.c
2 *
3 * Constuct and send DHCP server packets
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <string.h>
26#include <time.h>
27
28#include "packet.h"
29#include "debug.h"
30#include "dhcpd.h"
31#include "options.h"
32#include "leases.h"
33
34/* send a packet to giaddr using the kernel ip stack */
35static int send_packet_to_relay(struct dhcpMessage *payload)
36{
37 DEBUG(LOG_INFO, "Forwarding packet to relay");
38
39 return kernel_packet(payload, server_config.server, SERVER_PORT,
40 payload->giaddr, SERVER_PORT);
41}
42
43
44/* send a packet to a specific arp address and ip address by creating our own ip packet */
45static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast)
46{
47 unsigned char *chaddr;
48 u_int32_t ciaddr;
49
50 if (force_broadcast) {
51 DEBUG(LOG_INFO, "broadcasting packet to client (NAK)");
52 ciaddr = INADDR_BROADCAST;
53 chaddr = MAC_BCAST_ADDR;
54 } else if (payload->ciaddr) {
55 DEBUG(LOG_INFO, "unicasting packet to client ciaddr");
56 ciaddr = payload->ciaddr;
57 chaddr = payload->chaddr;
58 } else if (ntohs(payload->flags) & BROADCAST_FLAG) {
59 DEBUG(LOG_INFO, "broadcasting packet to client (requested)");
60 ciaddr = INADDR_BROADCAST;
61 chaddr = MAC_BCAST_ADDR;
62 } else {
63 DEBUG(LOG_INFO, "unicasting packet to client yiaddr");
64 ciaddr = payload->yiaddr;
65 chaddr = payload->chaddr;
66 }
67 return raw_packet(payload, server_config.server, SERVER_PORT,
68 ciaddr, CLIENT_PORT, chaddr, server_config.ifindex);
69}
70
71
72/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */
73static int send_packet(struct dhcpMessage *payload, int force_broadcast)
74{
75 int ret;
76
77 if (payload->giaddr)
78 ret = send_packet_to_relay(payload);
79 else ret = send_packet_to_client(payload, force_broadcast);
80 return ret;
81}
82
83
84static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type)
85{
86 init_header(packet, type);
87 packet->xid = oldpacket->xid;
88 memcpy(packet->chaddr, oldpacket->chaddr, 16);
89 packet->flags = oldpacket->flags;
90 packet->giaddr = oldpacket->giaddr;
91 packet->ciaddr = oldpacket->ciaddr;
92 add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server);
93}
94
95
96/* add in the bootp options */
97static void add_bootp_options(struct dhcpMessage *packet)
98{
99 packet->siaddr = server_config.siaddr;
100 if (server_config.sname)
101 strncpy(packet->sname, server_config.sname, sizeof(packet->sname) - 1);
102 if (server_config.boot_file)
103 strncpy(packet->file, server_config.boot_file, sizeof(packet->file) - 1);
104}
105
106
107/* send a DHCP OFFER to a DHCP DISCOVER */
108int sendOffer(struct dhcpMessage *oldpacket)
109{
110 struct dhcpMessage packet;
111 struct dhcpOfferedAddr *lease = NULL;
112 u_int32_t req_align, lease_time_align = server_config.lease;
113 unsigned char *req, *lease_time;
114 struct option_set *curr;
115 struct in_addr addr;
116
117 init_packet(&packet, oldpacket, DHCPOFFER);
118
119 /* ADDME: if static, short circuit */
120 /* the client is in our lease/offered table */
121 if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) {
122 if (!lease_expired(lease))
123 lease_time_align = lease->expires - time(0);
124 packet.yiaddr = lease->yiaddr;
125
126 /* Or the client has a requested ip */
127 } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) &&
128
129 /* Don't look here (ugly hackish thing to do) */
130 memcpy(&req_align, req, 4) &&
131
132 /* and the ip is in the lease range */
133 ntohl(req_align) >= ntohl(server_config.start) &&
134 ntohl(req_align) <= ntohl(server_config.end) &&
135
136 /* and its not already taken/offered */ /* ADDME: check that its not a static lease */
137 ((!(lease = find_lease_by_yiaddr(req_align)) ||
138
139 /* or its taken, but expired */ /* ADDME: or maybe in here */
140 lease_expired(lease)))) {
141 packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
142
143 /* otherwise, find a free IP */ /*ADDME: is it a static lease? */
144 } else {
145 packet.yiaddr = find_address(0);
146
147 /* try for an expired lease */
148 if (!packet.yiaddr) packet.yiaddr = find_address(1);
149 }
150
151 if(!packet.yiaddr) {
152 LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned");
153 return -1;
154 }
155
156 if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
157 LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned");
158 return -1;
159 }
160
161 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
162 memcpy(&lease_time_align, lease_time, 4);
163 lease_time_align = ntohl(lease_time_align);
164 if (lease_time_align > server_config.lease)
165 lease_time_align = server_config.lease;
166 }
167
168 /* Make sure we aren't just using the lease time from the previous offer */
169 if (lease_time_align < server_config.min_lease)
170 lease_time_align = server_config.lease;
171 /* ADDME: end of short circuit */
172 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
173
174 curr = server_config.options;
175 while (curr) {
176 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
177 add_option_string(packet.options, curr->data);
178 curr = curr->next;
179 }
180
181 add_bootp_options(&packet);
182
183 addr.s_addr = packet.yiaddr;
184 LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr));
185 return send_packet(&packet, 0);
186}
187
188
189int sendNAK(struct dhcpMessage *oldpacket)
190{
191 struct dhcpMessage packet;
192
193 init_packet(&packet, oldpacket, DHCPNAK);
194
195 DEBUG(LOG_INFO, "sending NAK");
196 return send_packet(&packet, 1);
197}
198
199
200int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr)
201{
202 struct dhcpMessage packet;
203 struct option_set *curr;
204 unsigned char *lease_time;
205 u_int32_t lease_time_align = server_config.lease;
206 struct in_addr addr;
207
208 init_packet(&packet, oldpacket, DHCPACK);
209 packet.yiaddr = yiaddr;
210
211 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
212 memcpy(&lease_time_align, lease_time, 4);
213 lease_time_align = ntohl(lease_time_align);
214 if (lease_time_align > server_config.lease)
215 lease_time_align = server_config.lease;
216 else if (lease_time_align < server_config.min_lease)
217 lease_time_align = server_config.lease;
218 }
219
220 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
221
222 curr = server_config.options;
223 while (curr) {
224 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
225 add_option_string(packet.options, curr->data);
226 curr = curr->next;
227 }
228
229 add_bootp_options(&packet);
230
231 addr.s_addr = packet.yiaddr;
232 LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr));
233
234 if (send_packet(&packet, 0) < 0)
235 return -1;
236
237 add_lease(packet.chaddr, packet.yiaddr, lease_time_align);
238
239 return 0;
240}
241
242
243int send_inform(struct dhcpMessage *oldpacket)
244{
245 struct dhcpMessage packet;
246 struct option_set *curr;
247
248 init_packet(&packet, oldpacket, DHCPACK);
249
250 curr = server_config.options;
251 while (curr) {
252 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
253 add_option_string(packet.options, curr->data);
254 curr = curr->next;
255 }
256
257 add_bootp_options(&packet);
258
259 return send_packet(&packet, 0);
260}
261
262
263
diff --git a/networking/udhcp/serverpacket.h b/networking/udhcp/serverpacket.h
new file mode 100644
index 000000000..5a4fb2768
--- /dev/null
+++ b/networking/udhcp/serverpacket.h
@@ -0,0 +1,11 @@
1#ifndef _SERVERPACKET_H
2#define _SERVERPACKET_H
3
4
5int sendOffer(struct dhcpMessage *oldpacket);
6int sendNAK(struct dhcpMessage *oldpacket);
7int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr);
8int send_inform(struct dhcpMessage *oldpacket);
9
10
11#endif
diff --git a/networking/udhcp/socket.c b/networking/udhcp/socket.c
new file mode 100644
index 000000000..3a2261561
--- /dev/null
+++ b/networking/udhcp/socket.c
@@ -0,0 +1,157 @@
1/*
2 * socket.c -- DHCP server client/server socket creation
3 *
4 * udhcp client/server
5 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
6 * Chris Trew <ctrew@moreton.com.au>
7 *
8 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/ioctl.h>
28#include <netinet/in.h>
29#include <unistd.h>
30#include <string.h>
31#include <arpa/inet.h>
32#include <net/if.h>
33#include <errno.h>
34#include <features.h>
35#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
36#include <netpacket/packet.h>
37#include <net/ethernet.h>
38#else
39#include <asm/types.h>
40#include <linux/if_packet.h>
41#include <linux/if_ether.h>
42#endif
43
44#include "debug.h"
45
46int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp)
47{
48 int fd;
49 struct ifreq ifr;
50 struct sockaddr_in *our_ip;
51
52 memset(&ifr, 0, sizeof(struct ifreq));
53 if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
54 ifr.ifr_addr.sa_family = AF_INET;
55 strcpy(ifr.ifr_name, interface);
56
57 if (addr) {
58 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
59 our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
60 *addr = our_ip->sin_addr.s_addr;
61 DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
62 } else {
63 LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %s",
64 strerror(errno));
65 return -1;
66 }
67 }
68
69 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
70 DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
71 *ifindex = ifr.ifr_ifindex;
72 } else {
73 LOG(LOG_ERR, "SIOCGIFINDEX failed!: %s", strerror(errno));
74 return -1;
75 }
76 if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
77 memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
78 DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
79 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
80 } else {
81 LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %s", strerror(errno));
82 return -1;
83 }
84 } else {
85 LOG(LOG_ERR, "socket failed!: %s", strerror(errno));
86 return -1;
87 }
88 close(fd);
89 return 0;
90}
91
92
93int listen_socket(unsigned int ip, int port, char *inf)
94{
95 struct ifreq interface;
96 int fd;
97 struct sockaddr_in addr;
98 int n = 1;
99
100 DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
101 if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
102 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
103 return -1;
104 }
105
106 memset(&addr, 0, sizeof(addr));
107 addr.sin_family = AF_INET;
108 addr.sin_port = htons(port);
109 addr.sin_addr.s_addr = ip;
110
111 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
112 close(fd);
113 return -1;
114 }
115 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) {
116 close(fd);
117 return -1;
118 }
119
120 strncpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
121 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) {
122 close(fd);
123 return -1;
124 }
125
126 if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
127 close(fd);
128 return -1;
129 }
130
131 return fd;
132}
133
134
135int raw_socket(int ifindex)
136{
137 int fd;
138 struct sockaddr_ll sock;
139
140 DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
141 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
142 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
143 return -1;
144 }
145
146 sock.sll_family = AF_PACKET;
147 sock.sll_protocol = htons(ETH_P_IP);
148 sock.sll_ifindex = ifindex;
149 if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
150 DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
151 close(fd);
152 return -1;
153 }
154
155 return fd;
156}
157
diff --git a/networking/udhcp/socket.h b/networking/udhcp/socket.h
new file mode 100644
index 000000000..333994b8f
--- /dev/null
+++ b/networking/udhcp/socket.h
@@ -0,0 +1,9 @@
1/* socket.h */
2#ifndef _SOCKET_H
3#define _SOCKET_H
4
5int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp);
6int listen_socket(unsigned int ip, int port, char *inf);
7int raw_socket(int ifindex);
8
9#endif
diff --git a/networking/udhcpc.c b/networking/udhcpc.c
deleted file mode 100644
index c05ca4557..000000000
--- a/networking/udhcpc.c
+++ /dev/null
@@ -1,1587 +0,0 @@
1/* dhcpd.c
2 *
3 * udhcp DHCP client
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * Converted to busybox by Glenn McGrath August 2002
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <stdio.h>
25#include <sys/time.h>
26#include <sys/types.h>
27#include <sys/file.h>
28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <signal.h>
35#include <time.h>
36#include <string.h>
37#include <sys/ioctl.h>
38#include <net/if.h>
39#include <errno.h>
40#include <netinet/ip.h>
41#include <netinet/udp.h>
42#include <sys/types.h>
43#include <sys/wait.h>
44
45#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
46#include <netpacket/packet.h>
47#include <net/ethernet.h>
48#else
49#include <asm/types.h>
50#include <linux/if_packet.h>
51#include <linux/if_ether.h>
52#endif
53#include "libbb.h"
54
55static int state;
56static unsigned long requested_ip; /* = 0 */
57static unsigned long server_addr;
58static unsigned long timeout;
59static int packet_num; /* = 0 */
60static int fd_main;
61
62/* #define DEBUG */
63
64#define VERSION "0.9.7"
65
66#define LISTEN_NONE 0
67#define LISTEN_KERNEL 1
68#define LISTEN_RAW 2
69static int listen_mode;
70
71#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
72
73#define DHCP_END 0xFF
74#define TYPE_MASK 0x0F
75#define BROADCAST_FLAG 0x8000
76
77#define SERVER_PORT 67
78
79#define DHCP_MAGIC 0x63825363
80
81#define BOOTREQUEST 1
82#define BOOTREPLY 2
83
84#define ETH_10MB 1
85#define ETH_10MB_LEN 6
86
87#define OPTION_FIELD 0
88#define FILE_FIELD 1
89#define SNAME_FIELD 2
90
91#define INIT_SELECTING 0
92#define REQUESTING 1
93#define BOUND 2
94#define RENEWING 3
95#define REBINDING 4
96#define INIT_REBOOT 5
97#define RENEW_REQUESTED 6
98#define RELEASED 7
99
100#define CLIENT_PORT 68
101
102#define DHCPDISCOVER 1
103#define DHCPOFFER 2
104#define DHCPREQUEST 3
105#define DHCPDECLINE 4
106#define DHCPACK 5
107#define DHCPNAK 6
108#define DHCPRELEASE 7
109#define DHCPINFORM 8
110
111/* DHCP option codes (partial list) */
112#define DHCP_PADDING 0x00
113#define DHCP_SUBNET 0x01
114#define DHCP_TIME_OFFSET 0x02
115#define DHCP_ROUTER 0x03
116#define DHCP_TIME_SERVER 0x04
117#define DHCP_NAME_SERVER 0x05
118#define DHCP_DNS_SERVER 0x06
119#define DHCP_LOG_SERVER 0x07
120#define DHCP_COOKIE_SERVER 0x08
121#define DHCP_LPR_SERVER 0x09
122#define DHCP_HOST_NAME 0x0c
123#define DHCP_BOOT_SIZE 0x0d
124#define DHCP_DOMAIN_NAME 0x0f
125#define DHCP_SWAP_SERVER 0x10
126#define DHCP_ROOT_PATH 0x11
127#define DHCP_IP_TTL 0x17
128#define DHCP_MTU 0x1a
129#define DHCP_BROADCAST 0x1c
130#define DHCP_NTP_SERVER 0x2a
131#define DHCP_WINS_SERVER 0x2c
132#define DHCP_REQUESTED_IP 0x32
133#define DHCP_LEASE_TIME 0x33
134#define DHCP_OPTION_OVER 0x34
135#define DHCP_MESSAGE_TYPE 0x35
136#define DHCP_SERVER_ID 0x36
137#define DHCP_PARAM_REQ 0x37
138#define DHCP_MESSAGE 0x38
139#define DHCP_MAX_SIZE 0x39
140#define DHCP_T1 0x3a
141#define DHCP_T2 0x3b
142#define DHCP_VENDOR 0x3c
143#define DHCP_CLIENT_ID 0x3d
144
145/* miscellaneous defines */
146#define MAC_BCAST_ADDR (unsigned char *) "\xff\xff\xff\xff\xff\xff"
147#define OPT_CODE 0
148#define OPT_LEN 1
149#define OPT_DATA 2
150
151enum {
152 OPTION_IP = 1,
153 OPTION_IP_PAIR,
154 OPTION_STRING,
155 OPTION_BOOLEAN,
156 OPTION_U8,
157 OPTION_U16,
158 OPTION_S16,
159 OPTION_U32,
160 OPTION_S32
161};
162
163#define OPTION_REQ 0x10 /* have the client request this option */
164#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
165
166#ifdef SYSLOG
167# define LOG(level, str, args...) do { printf(str, ## args); \
168 printf("\n"); \
169 syslog(level, str, ## args); } while(0)
170# define OPEN_LOG(name) openlog(name, 0, 0)
171# define CLOSE_LOG() closelog()
172#else
173# define LOG_EMERG "EMERGENCY!"
174# define LOG_ALERT "ALERT!"
175# define LOG_CRIT "critical!"
176# define LOG_WARNING "warning"
177# define LOG_ERR "error"
178# define LOG_INFO "info"
179# define LOG_DEBUG "debug"
180# define LOG(level, str, args...) do { printf("%s, " str "\n", level, ## args); } while(0)
181# define OPEN_LOG(name)
182# define CLOSE_LOG()
183#endif
184
185#ifdef DEBUG
186# undef DEBUG
187# define DEBUG(level, str, args...) LOG(level, str, ## args)
188# define DEBUGGING
189#else
190# define DEBUG(level, str, args...)
191#endif
192
193struct dhcpMessage {
194 u_int8_t op;
195 u_int8_t htype;
196 u_int8_t hlen;
197 u_int8_t hops;
198 u_int32_t xid;
199 u_int16_t secs;
200 u_int16_t flags;
201 u_int32_t ciaddr;
202 u_int32_t yiaddr;
203 u_int32_t siaddr;
204 u_int32_t giaddr;
205 u_int8_t chaddr[16];
206 u_int8_t sname[64];
207 u_int8_t file[128];
208 u_int32_t cookie;
209 u_int8_t options[308]; /* 312 - cookie */
210};
211
212struct client_config_t {
213 char foreground; /* Do not fork */
214 char quit_after_lease; /* Quit after obtaining lease */
215 char abort_if_no_lease; /* Abort if no lease */
216 char *interface; /* The name of the interface to use */
217 char *pidfile; /* Optionally store the process ID */
218 char *script; /* User script to run at dhcp events */
219 unsigned char *clientid; /* Optional client id to use */
220 unsigned char *hostname; /* Optional hostname to use */
221 int ifindex; /* Index number of the interface to use */
222 unsigned char arp[6]; /* Our arp address */
223};
224
225struct client_config_t client_config = {
226 /* Default options. */
227 abort_if_no_lease:0,
228 foreground:0,
229 quit_after_lease:0,
230 interface:"eth0",
231 pidfile:NULL,
232 script:DEFAULT_SCRIPT,
233 clientid:NULL,
234 hostname:NULL,
235 ifindex:0,
236 arp:"\0\0\0\0\0\0", /* appease gcc-3.0 */
237};
238
239struct dhcp_option {
240 char name[10];
241 char flags;
242 unsigned char code;
243};
244
245struct udp_dhcp_packet {
246 struct iphdr ip;
247 struct udphdr udp;
248 struct dhcpMessage data;
249};
250
251static const struct dhcp_option options[] = {
252 /* name[10] flags code */
253 {"subnet", OPTION_IP | OPTION_REQ, 0x01},
254 {"timezone", OPTION_S32, 0x02},
255 {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03},
256 {"timesvr", OPTION_IP | OPTION_LIST, 0x04},
257 {"namesvr", OPTION_IP | OPTION_LIST, 0x05},
258 {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06},
259 {"logsvr", OPTION_IP | OPTION_LIST, 0x07},
260 {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08},
261 {"lprsvr", OPTION_IP | OPTION_LIST, 0x09},
262 {"hostname", OPTION_STRING | OPTION_REQ, 0x0c},
263 {"bootsize", OPTION_U16, 0x0d},
264 {"domain", OPTION_STRING | OPTION_REQ, 0x0f},
265 {"swapsvr", OPTION_IP, 0x10},
266 {"rootpath", OPTION_STRING, 0x11},
267 {"ipttl", OPTION_U8, 0x17},
268 {"mtu", OPTION_U16, 0x1a},
269 {"broadcast", OPTION_IP | OPTION_REQ, 0x1c},
270 {"ntpsrv", OPTION_IP | OPTION_LIST, 0x2a},
271 {"wins", OPTION_IP | OPTION_LIST, 0x2c},
272 {"requestip", OPTION_IP, 0x32},
273 {"lease", OPTION_U32, 0x33},
274 {"dhcptype", OPTION_U8, 0x35},
275 {"serverid", OPTION_IP, 0x36},
276 {"message", OPTION_STRING, 0x38},
277 {"tftp", OPTION_STRING, 0x42},
278 {"bootfile", OPTION_STRING, 0x43},
279 {"", 0x00, 0x00}
280};
281
282/* Lengths of the different option types */
283static const unsigned char option_lengths[] = {
284 [OPTION_IP] = 4,
285 [OPTION_IP_PAIR] = 8,
286 [OPTION_BOOLEAN] = 1,
287 [OPTION_STRING] = 1,
288 [OPTION_U8] = 1,
289 [OPTION_U16] = 2,
290 [OPTION_S16] = 2,
291 [OPTION_U32] = 4,
292 [OPTION_S32] = 4
293};
294
295/* get a rough idea of how long an option will be (rounding up...) */
296static const unsigned char max_option_length[] = {
297 [OPTION_IP] = sizeof("255.255.255.255 "),
298 [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
299 [OPTION_STRING] = 1,
300 [OPTION_BOOLEAN] = sizeof("yes "),
301 [OPTION_U8] = sizeof("255 "),
302 [OPTION_U16] = sizeof("65535 "),
303 [OPTION_S16] = sizeof("-32768 "),
304 [OPTION_U32] = sizeof("4294967295 "),
305 [OPTION_S32] = sizeof("-2147483684 "),
306};
307
308/* return the position of the 'end' option (no bounds checking) */
309static int end_option(unsigned char *optionptr)
310{
311 int i = 0;
312
313 while (optionptr[i] != DHCP_END) {
314 if (optionptr[i] == DHCP_PADDING)
315 i++;
316 else
317 i += optionptr[i + OPT_LEN] + 2;
318 }
319 return i;
320}
321
322/* add an option string to the options (an option string contains an option code,
323 * length, then data) */
324static int add_option_string(unsigned char *optionptr, unsigned char *string)
325{
326 int end = end_option(optionptr);
327
328 /* end position + string length + option code/length + end option */
329 if (end + string[OPT_LEN] + 2 + 1 >= 308) {
330 LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!",
331 string[OPT_CODE]);
332 return 0;
333 }
334 DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);
335 memcpy(optionptr + end, string, string[OPT_LEN] + 2);
336 optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
337 return string[OPT_LEN] + 2;
338}
339
340/* add a one to four byte option to a packet */
341static int add_simple_option(unsigned char *optionptr, unsigned char code,
342 u_int32_t data)
343{
344 char length = 0;
345 int i;
346 unsigned char option[2 + 4];
347 unsigned char *u8;
348 u_int16_t *u16;
349 u_int32_t *u32;
350 u_int32_t aligned;
351
352 u8 = (unsigned char *) &aligned;
353 u16 = (u_int16_t *) & aligned;
354 u32 = &aligned;
355
356 for (i = 0; options[i].code; i++)
357 if (options[i].code == code) {
358 length = option_lengths[options[i].flags & TYPE_MASK];
359 }
360
361 if (!length) {
362 DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
363 return 0;
364 }
365
366 option[OPT_CODE] = code;
367 option[OPT_LEN] = length;
368
369 switch (length) {
370 case 1:
371 *u8 = data;
372 break;
373 case 2:
374 *u16 = data;
375 break;
376 case 4:
377 *u32 = data;
378 break;
379 }
380
381 memcpy(option + 2, &aligned, length);
382 return add_option_string(optionptr, option);
383}
384
385static u_int16_t checksum(void *addr, int count)
386{
387 /* Compute Internet Checksum for "count" bytes
388 * beginning at location "addr".
389 */
390 register int32_t sum = 0;
391 u_int16_t *source = (u_int16_t *) addr;
392
393 while (count > 1) {
394 /* This is the inner loop */
395 sum += *source++;
396 count -= 2;
397 }
398
399 /* Add left-over byte, if any */
400 if (count > 0) {
401 sum += *(unsigned char *) source;
402 }
403
404 /* Fold 32-bit sum to 16 bits */
405 while (sum >> 16) {
406 sum = (sum & 0xffff) + (sum >> 16);
407 }
408
409 return ~sum;
410}
411
412/* Constuct a ip/udp header for a packet, and specify the source and dest hardware address */
413static int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip,
414 int source_port, u_int32_t dest_ip, int dest_port,
415 unsigned char *dest_arp, int ifindex)
416{
417 int l_fd;
418 int result;
419 struct sockaddr_ll dest;
420 struct udp_dhcp_packet packet;
421
422 if ((l_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
423 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
424 return -1;
425 }
426
427 memset(&dest, 0, sizeof(dest));
428 memset(&packet, 0, sizeof(packet));
429
430 dest.sll_family = AF_PACKET;
431 dest.sll_protocol = htons(ETH_P_IP);
432 dest.sll_ifindex = ifindex;
433 dest.sll_halen = 6;
434 memcpy(dest.sll_addr, dest_arp, 6);
435 if (bind(l_fd, (struct sockaddr *) &dest, sizeof(struct sockaddr_ll)) < 0) {
436 DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
437 close(l_fd);
438 return -1;
439 }
440
441 packet.ip.protocol = IPPROTO_UDP;
442 packet.ip.saddr = source_ip;
443 packet.ip.daddr = dest_ip;
444 packet.udp.source = htons(source_port);
445 packet.udp.dest = htons(dest_port);
446 packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
447 packet.ip.tot_len = packet.udp.len;
448 memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
449 packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
450
451 packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
452 packet.ip.ihl = sizeof(packet.ip) >> 2;
453 packet.ip.version = IPVERSION;
454 packet.ip.ttl = IPDEFTTL;
455 packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
456
457 result =
458 sendto(l_fd, &packet, sizeof(struct udp_dhcp_packet), 0,
459 (struct sockaddr *) &dest, sizeof(dest));
460 if (result <= 0) {
461 DEBUG(LOG_ERR, "write on socket failed: %s", strerror(errno));
462 }
463 close(l_fd);
464 return result;
465}
466
467/* Let the kernel do all the work for packet generation */
468static int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip,
469 int source_port, u_int32_t dest_ip, int dest_port)
470{
471 int n = 1;
472 int l_fd, result;
473 struct sockaddr_in client;
474
475 if ((l_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
476 return -1;
477 }
478
479 if (setsockopt(l_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) ==
480 -1) {
481 return -1;
482 }
483
484 memset(&client, 0, sizeof(client));
485 client.sin_family = AF_INET;
486 client.sin_port = htons(source_port);
487 client.sin_addr.s_addr = source_ip;
488
489 if (bind(l_fd, (struct sockaddr *) &client, sizeof(struct sockaddr)) ==
490 -1) {
491 return -1;
492 }
493
494 memset(&client, 0, sizeof(client));
495 client.sin_family = AF_INET;
496 client.sin_port = htons(dest_port);
497 client.sin_addr.s_addr = dest_ip;
498
499 if (connect(l_fd, (struct sockaddr *) &client, sizeof(struct sockaddr)) ==
500 -1) {
501 return -1;
502 }
503
504 result = write(l_fd, payload, sizeof(struct dhcpMessage));
505 close(l_fd);
506 return result;
507}
508
509/* initialize a packet with the proper defaults */
510static void init_packet(struct dhcpMessage *packet, char type)
511{
512 struct vendor {
513 char vendor, length;
514 char str[sizeof("udhcp " VERSION)];
515 }
516 vendor_id = {
517 DHCP_VENDOR, sizeof("udhcp " VERSION) - 1, "udhcp " VERSION};
518
519 memset(packet, 0, sizeof(struct dhcpMessage));
520 switch (type) {
521 case DHCPDISCOVER:
522 case DHCPREQUEST:
523 case DHCPRELEASE:
524 case DHCPINFORM:
525 packet->op = BOOTREQUEST;
526 break;
527 case DHCPOFFER:
528 case DHCPACK:
529 case DHCPNAK:
530 packet->op = BOOTREPLY;
531 }
532 packet->htype = ETH_10MB;
533 packet->hlen = ETH_10MB_LEN;
534 packet->cookie = htonl(DHCP_MAGIC);
535 packet->options[0] = DHCP_END;
536 add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
537
538 memcpy(packet->chaddr, client_config.arp, 6);
539 add_option_string(packet->options, client_config.clientid);
540 if (client_config.hostname) {
541 add_option_string(packet->options, client_config.hostname);
542 }
543 add_option_string(packet->options, (unsigned char *) &vendor_id);
544}
545
546
547/* Add a paramater request list for stubborn DHCP servers. Pull the data
548 * from the struct in options.c. Don't do bounds checking here because it
549 * goes towards the head of the packet. */
550static void add_requests(struct dhcpMessage *packet)
551{
552 int end = end_option(packet->options);
553 int i, len = 0;
554
555 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
556 for (i = 0; options[i].code; i++) {
557 if (options[i].flags & OPTION_REQ) {
558 packet->options[end + OPT_DATA + len++] = options[i].code;
559 }
560 }
561 packet->options[end + OPT_LEN] = len;
562 packet->options[end + OPT_DATA + len] = DHCP_END;
563
564}
565
566/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
567static inline int send_discover(unsigned long xid, unsigned long requested)
568{
569 struct dhcpMessage packet;
570
571 init_packet(&packet, DHCPDISCOVER);
572 packet.xid = xid;
573 if (requested) {
574 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
575 }
576 add_requests(&packet);
577 DEBUG(LOG_DEBUG, "Sending discover...");
578 return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
579 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
580}
581
582/* Broadcasts a DHCP request message */
583static inline int send_selecting(unsigned long xid, unsigned long server,
584 unsigned long requested)
585{
586 struct dhcpMessage packet;
587 struct in_addr addr;
588
589 init_packet(&packet, DHCPREQUEST);
590 packet.xid = xid;
591
592 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
593 add_simple_option(packet.options, DHCP_SERVER_ID, server);
594
595 add_requests(&packet);
596 addr.s_addr = requested;
597 DEBUG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr));
598 return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
599 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
600}
601
602
603/* Unicasts or broadcasts a DHCP renew message */
604static int send_renew(unsigned long xid, unsigned long server,
605 unsigned long ciaddr)
606{
607 struct dhcpMessage packet;
608
609 init_packet(&packet, DHCPREQUEST);
610 packet.xid = xid;
611 packet.ciaddr = ciaddr;
612
613 add_requests(&packet);
614 DEBUG(LOG_DEBUG, "Sending renew...");
615 if (server) {
616 return kernel_packet(&packet, ciaddr, CLIENT_PORT, server,
617 SERVER_PORT);
618 }
619 return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
620 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
621}
622
623/* Create a random xid */
624static unsigned long random_xid(void)
625{
626 static int initialized;
627
628 if (!initialized) {
629 srand(time(0));
630 initialized++;
631 }
632 return rand();
633}
634
635/* just a little helper */
636static void change_mode(int new_mode)
637{
638 DEBUG(LOG_INFO, "entering %s listen mode",
639 new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
640 close(fd_main);
641 fd_main = -1;
642 listen_mode = new_mode;
643}
644
645
646/* SIGUSR1 handler (renew) */
647static void renew_requested(int sig)
648{
649 sig = 0;
650 LOG(LOG_INFO, "Received SIGUSR1");
651 if (state == BOUND || state == RENEWING || state == REBINDING ||
652 state == RELEASED) {
653 change_mode(LISTEN_KERNEL);
654 packet_num = 0;
655 state = RENEW_REQUESTED;
656 }
657
658 if (state == RELEASED) {
659 change_mode(LISTEN_RAW);
660 state = INIT_SELECTING;
661 }
662
663 /* Kill any timeouts because the user wants this to hurry along */
664 timeout = 0;
665}
666
667/* get an option with bounds checking (warning, not aligned). */
668static unsigned char *get_option(struct dhcpMessage *packet, int code)
669{
670 int i, length;
671 unsigned char *optionptr;
672 int over = 0, done = 0, curr = OPTION_FIELD;
673
674 optionptr = packet->options;
675 i = 0;
676 length = 308;
677 while (!done) {
678 if (i >= length) {
679 LOG(LOG_WARNING, "bogus packet, option fields too long.");
680 return NULL;
681 }
682 if (optionptr[i + OPT_CODE] == code) {
683 if (i + 1 + optionptr[i + OPT_LEN] >= length) {
684 LOG(LOG_WARNING, "bogus packet, option fields too long.");
685 return NULL;
686 }
687 return optionptr + i + 2;
688 }
689 switch (optionptr[i + OPT_CODE]) {
690 case DHCP_PADDING:
691 i++;
692 break;
693 case DHCP_OPTION_OVER:
694 if (i + 1 + optionptr[i + OPT_LEN] >= length) {
695 LOG(LOG_WARNING, "bogus packet, option fields too long.");
696 return NULL;
697 }
698 over = optionptr[i + 3];
699 i += optionptr[OPT_LEN] + 2;
700 break;
701 case DHCP_END:
702 if (curr == OPTION_FIELD && over & FILE_FIELD) {
703 optionptr = packet->file;
704 i = 0;
705 length = 128;
706 curr = FILE_FIELD;
707 } else if (curr == FILE_FIELD && over & SNAME_FIELD) {
708 optionptr = packet->sname;
709 i = 0;
710 length = 64;
711 curr = SNAME_FIELD;
712 } else {
713 done = 1;
714 }
715 break;
716 default:
717 i += optionptr[OPT_LEN + i] + 2;
718 }
719 }
720 return NULL;
721}
722
723static int sprintip(char *dest, char *pre, unsigned char *ip)
724{
725 return sprintf(dest, "%s%d.%d.%d.%d ", pre, ip[0], ip[1], ip[2], ip[3]);
726}
727
728
729/* Fill dest with the text of option 'option'. */
730static inline void fill_options(char *dest, unsigned char *option,
731 const struct dhcp_option *type_p)
732{
733 int type, optlen;
734 u_int16_t val_u16;
735 int16_t val_s16;
736 u_int32_t val_u32;
737 int32_t val_s32;
738 int len = option[OPT_LEN - 2];
739
740 dest += sprintf(dest, "%s=", type_p->name);
741
742 type = type_p->flags & TYPE_MASK;
743 optlen = option_lengths[type];
744 for (;;) {
745 switch (type) {
746 case OPTION_IP_PAIR:
747 dest += sprintip(dest, "", option);
748 *(dest++) = '/';
749 option += 4;
750 optlen = 4;
751 case OPTION_IP: /* Works regardless of host byte order. */
752 dest += sprintip(dest, "", option);
753 break;
754 case OPTION_BOOLEAN:
755 dest += sprintf(dest, *option ? "yes " : "no ");
756 break;
757 case OPTION_U8:
758 dest += sprintf(dest, "%u ", *option);
759 break;
760 case OPTION_U16:
761 memcpy(&val_u16, option, 2);
762 dest += sprintf(dest, "%u ", ntohs(val_u16));
763 break;
764 case OPTION_S16:
765 memcpy(&val_s16, option, 2);
766 dest += sprintf(dest, "%d ", ntohs(val_s16));
767 break;
768 case OPTION_U32:
769 memcpy(&val_u32, option, 4);
770 dest += sprintf(dest, "%lu ", (unsigned long) ntohl(val_u32));
771 break;
772 case OPTION_S32:
773 memcpy(&val_s32, option, 4);
774 dest += sprintf(dest, "%ld ", (long) ntohl(val_s32));
775 break;
776 case OPTION_STRING:
777 memcpy(dest, option, len);
778 dest[len] = '\0';
779 return; /* Short circuit this case */
780 }
781 option += optlen;
782 len -= optlen;
783 if (len <= 0) {
784 break;
785 }
786 }
787}
788
789static char *find_env(const char *prefix, char *defaultstr)
790{
791 extern char **environ;
792 char **ptr;
793 const int len = strlen(prefix);
794
795 for (ptr = environ; *ptr != NULL; ptr++) {
796 if (strncmp(prefix, *ptr, len) == 0) {
797 return *ptr;
798 }
799 }
800 return defaultstr;
801}
802
803/* put all the paramaters into an environment */
804static char **fill_envp(struct dhcpMessage *packet)
805{
806 /* supported options are easily added here */
807 int num_options = 0;
808 int i, j;
809 char **envp;
810 unsigned char *temp;
811 char over = 0;
812
813 if (packet == NULL) {
814 num_options = 0;
815 } else {
816 for (i = 0; options[i].code; i++) {
817 if (get_option(packet, options[i].code)) {
818 num_options++;
819 }
820 }
821 if (packet->siaddr) {
822 num_options++;
823 }
824 if ((temp = get_option(packet, DHCP_OPTION_OVER))) {
825 over = *temp;
826 }
827 if (!(over & FILE_FIELD) && packet->file[0]) {
828 num_options++;
829 }
830 if (!(over & SNAME_FIELD) && packet->sname[0]) {
831 num_options++;
832 }
833 }
834
835 envp = xmalloc((num_options + 5) * sizeof(char *));
836 envp[0] = xmalloc(sizeof("interface=") + strlen(client_config.interface));
837 sprintf(envp[0], "interface=%s", client_config.interface);
838 envp[1] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");
839 envp[2] = find_env("HOME", "HOME=/");
840
841 if (packet == NULL) {
842 envp[3] = NULL;
843 return envp;
844 }
845
846 envp[3] = xmalloc(sizeof("ip=255.255.255.255"));
847 sprintip(envp[3], "ip=", (unsigned char *) &packet->yiaddr);
848 for (i = 0, j = 4; options[i].code; i++) {
849 if ((temp = get_option(packet, options[i].code))) {
850 envp[j] =
851 xmalloc(max_option_length[(&options[i])->flags & TYPE_MASK] *
852 (temp[OPT_LEN - 2] /
853 option_lengths[(&options[i])->flags & TYPE_MASK]) +
854 strlen((&options[i])->name) + 2);
855 fill_options(envp[j], temp, &options[i]);
856 j++;
857 }
858 }
859 if (packet->siaddr) {
860 envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));
861 sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->yiaddr);
862 }
863 if (!(over & FILE_FIELD) && packet->file[0]) {
864 /* watch out for invalid packets */
865 packet->file[sizeof(packet->file) - 1] = '\0';
866 envp[j] = xmalloc(sizeof("boot_file=") + strlen(packet->file));
867 sprintf(envp[j++], "boot_file=%s", packet->file);
868 }
869 if (!(over & SNAME_FIELD) && packet->sname[0]) {
870 /* watch out for invalid packets */
871 packet->sname[sizeof(packet->sname) - 1] = '\0';
872 envp[j] = xmalloc(sizeof("sname=") + strlen(packet->sname));
873 sprintf(envp[j++], "sname=%s", packet->sname);
874 }
875 envp[j] = NULL;
876 return envp;
877}
878
879/* Call a script with a par file and env vars */
880static void run_script(struct dhcpMessage *packet, const char *name)
881{
882 int pid;
883 char **envp;
884
885 if (client_config.script == NULL) {
886 return;
887 }
888
889 /* call script */
890 pid = fork();
891 if (pid) {
892 waitpid(pid, NULL, 0);
893 return;
894 } else if (pid == 0) {
895 envp = fill_envp(packet);
896
897 /* close fd's? */
898
899 /* exec script */
900 DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
901 execle(client_config.script, client_config.script, name, NULL, envp);
902 LOG(LOG_ERR, "script %s failed: %s",
903 client_config.script, strerror(errno));
904 exit(1);
905 }
906}
907
908/* SIGUSR2 handler (release) */
909static void release_requested(int sig)
910{
911 sig = 0;
912 LOG(LOG_INFO, "Received SIGUSR2");
913 /* send release packet */
914 if (state == BOUND || state == RENEWING || state == REBINDING) {
915 struct dhcpMessage packet;
916
917 init_packet(&packet, DHCPRELEASE);
918 packet.xid = random_xid();
919 packet.ciaddr = requested_ip;
920
921 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested_ip);
922 add_simple_option(packet.options, DHCP_SERVER_ID, server_addr);
923
924 DEBUG(LOG_DEBUG, "Sending release...");
925 kernel_packet(&packet, requested_ip, CLIENT_PORT, server_addr,
926 SERVER_PORT);
927 run_script(NULL, "deconfig");
928 }
929
930 change_mode(LISTEN_NONE);
931 state = RELEASED;
932 timeout = 0x7fffffff;
933}
934
935
936static int pidfile_acquire(char *pidfile)
937{
938 int pid_fd;
939
940 if (pidfile == NULL) {
941 return -1;
942 }
943 pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644);
944 if (pid_fd < 0) {
945 LOG(LOG_ERR, "Unable to open pidfile %s: %s\n",
946 pidfile, strerror(errno));
947 } else {
948 lockf(pid_fd, F_LOCK, 0);
949 }
950
951 return pid_fd;
952}
953
954
955static void pidfile_write_release(int pid_fd)
956{
957 FILE *out;
958
959 if (pid_fd < 0) {
960 return;
961 }
962 if ((out = fdopen(pid_fd, "w")) != NULL) {
963 fprintf(out, "%d\n", getpid());
964 fclose(out);
965 }
966 lockf(pid_fd, F_UNLCK, 0);
967 close(pid_fd);
968}
969
970/* Exit and cleanup */
971static void exit_client(int retval)
972{
973 unlink(client_config.pidfile);
974 if (client_config.pidfile) {
975 unlink(client_config.pidfile);
976 }
977 CLOSE_LOG();
978 exit(retval);
979}
980
981
982/* SIGTERM handler */
983static void terminate(int sig)
984{
985 sig = 0;
986 LOG(LOG_INFO, "Received SIGTERM");
987 exit_client(0);
988}
989
990
991static inline int read_interface(char *interface, int *ifindex,
992 u_int32_t * addr, unsigned char *arp)
993{
994 int l_fd;
995 struct ifreq ifr;
996 struct sockaddr_in *s_in;
997
998 memset(&ifr, 0, sizeof(struct ifreq));
999 if ((l_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
1000 ifr.ifr_addr.sa_family = AF_INET;
1001 strcpy(ifr.ifr_name, interface);
1002
1003 if (addr) {
1004 if (ioctl(l_fd, SIOCGIFADDR, &ifr) == 0) {
1005 s_in = (struct sockaddr_in *) &ifr.ifr_addr;
1006 *addr = s_in->sin_addr.s_addr;
1007 DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name,
1008 inet_ntoa(s_in->sin_addr));
1009 } else {
1010 LOG(LOG_ERR, "SIOCGIFADDR failed!: %s", strerror(errno));
1011 return -1;
1012 }
1013 }
1014
1015 if (ioctl(l_fd, SIOCGIFINDEX, &ifr) == 0) {
1016 DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
1017 *ifindex = ifr.ifr_ifindex;
1018 } else {
1019 LOG(LOG_ERR, "SIOCGIFINDEX failed!: %s", strerror(errno));
1020 return -1;
1021 }
1022 if (ioctl(l_fd, SIOCGIFHWADDR, &ifr) == 0) {
1023 memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
1024 DEBUG(LOG_INFO,
1025 "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
1026 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
1027 } else {
1028 LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %s", strerror(errno));
1029 return -1;
1030 }
1031 } else {
1032 LOG(LOG_ERR, "socket failed!: %s", strerror(errno));
1033 return -1;
1034 }
1035 close(l_fd);
1036 return 0;
1037}
1038
1039
1040static inline int listen_socket(unsigned int ip, int port, char *inf)
1041{
1042 struct ifreq interface;
1043 int l_fd;
1044 struct sockaddr_in addr;
1045 int n = 1;
1046
1047 DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
1048 if ((l_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
1049 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
1050 return -1;
1051 }
1052
1053 memset(&addr, 0, sizeof(addr));
1054 addr.sin_family = AF_INET;
1055 addr.sin_port = htons(port);
1056 addr.sin_addr.s_addr = ip;
1057
1058 if (setsockopt(l_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) ==
1059 -1) {
1060 close(l_fd);
1061 return -1;
1062 }
1063 if (setsockopt(l_fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) ==
1064 -1) {
1065 close(l_fd);
1066 return -1;
1067 }
1068
1069 strncpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
1070 if (setsockopt
1071 (l_fd, SOL_SOCKET, SO_BINDTODEVICE, (char *) &interface,
1072 sizeof(interface)) < 0) {
1073 close(l_fd);
1074 return -1;
1075 }
1076
1077 if (bind(l_fd, (struct sockaddr *) &addr, sizeof(struct sockaddr)) == -1) {
1078 close(l_fd);
1079 return -1;
1080 }
1081
1082 return l_fd;
1083}
1084
1085
1086static int raw_socket(int ifindex)
1087{
1088 int l_fd;
1089 struct sockaddr_ll sock;
1090
1091 DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
1092 if ((l_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
1093 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
1094 return -1;
1095 }
1096
1097 sock.sll_family = AF_PACKET;
1098 sock.sll_protocol = htons(ETH_P_IP);
1099 sock.sll_ifindex = ifindex;
1100 if (bind(l_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
1101 DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
1102 close(l_fd);
1103 return -1;
1104 }
1105
1106 return l_fd;
1107
1108}
1109
1110/* read a packet from socket fd, return -1 on read error, -2 on packet error */
1111static int get_packet(struct dhcpMessage *packet, int l_fd)
1112{
1113 int bytes;
1114 int i;
1115 const char broken_vendors[][8] = {
1116 "MSFT 98",
1117 ""
1118 };
1119 char unsigned *vendor;
1120
1121 memset(packet, 0, sizeof(struct dhcpMessage));
1122 bytes = read(l_fd, packet, sizeof(struct dhcpMessage));
1123 if (bytes < 0) {
1124 DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
1125 return -1;
1126 }
1127
1128 if (ntohl(packet->cookie) != DHCP_MAGIC) {
1129 LOG(LOG_ERR, "received bogus message, ignoring");
1130 return -2;
1131 }
1132 DEBUG(LOG_INFO, "Received a packet");
1133
1134 if (packet->op == BOOTREQUEST
1135 && (vendor = get_option(packet, DHCP_VENDOR))) {
1136 for (i = 0; broken_vendors[i][0]; i++) {
1137 if (vendor[OPT_LEN - 2] ==
1138 (unsigned char) strlen(broken_vendors[i])
1139 && !strncmp(vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
1140 DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
1141 broken_vendors[i]);
1142 packet->flags |= htons(BROADCAST_FLAG);
1143 }
1144 }
1145 }
1146
1147 return bytes;
1148}
1149
1150static inline int get_raw_packet(struct dhcpMessage *payload, int l_fd)
1151{
1152 int bytes;
1153 struct udp_dhcp_packet packet;
1154 u_int32_t source, dest;
1155 u_int16_t check;
1156
1157 memset(&packet, 0, sizeof(struct udp_dhcp_packet));
1158 bytes = read(l_fd, &packet, sizeof(struct udp_dhcp_packet));
1159 if (bytes < 0) {
1160 DEBUG(LOG_INFO, "couldn't read on raw listening socket -- ignoring");
1161 usleep(500000); /* possible down interface, looping condition */
1162 return -1;
1163 }
1164
1165 if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
1166 DEBUG(LOG_INFO, "message too short, ignoring");
1167 return -1;
1168 }
1169
1170 if (bytes < ntohs(packet.ip.tot_len)) {
1171 DEBUG(LOG_INFO, "Truncated packet");
1172 return -1;
1173 }
1174
1175 /* ignore any extra garbage bytes */
1176 bytes = ntohs(packet.ip.tot_len);
1177
1178 /* Make sure its the right packet for us, and that it passes sanity checks */
1179 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION ||
1180 packet.ip.ihl != sizeof(packet.ip) >> 2
1181 || packet.udp.dest != htons(CLIENT_PORT)
1182 || bytes > (int) sizeof(struct udp_dhcp_packet)
1183 || ntohs(packet.udp.len) != (short) (bytes - sizeof(packet.ip))) {
1184 DEBUG(LOG_INFO, "unrelated/bogus packet");
1185 return -1;
1186 }
1187
1188 /* check IP checksum */
1189 check = packet.ip.check;
1190 packet.ip.check = 0;
1191 if (check != checksum(&(packet.ip), sizeof(packet.ip))) {
1192 DEBUG(LOG_INFO, "bad IP header checksum, ignoring");
1193 return -1;
1194 }
1195
1196 /* verify the UDP checksum by replacing the header with a psuedo header */
1197 source = packet.ip.saddr;
1198 dest = packet.ip.daddr;
1199 check = packet.udp.check;
1200 packet.udp.check = 0;
1201 memset(&packet.ip, 0, sizeof(packet.ip));
1202
1203 packet.ip.protocol = IPPROTO_UDP;
1204 packet.ip.saddr = source;
1205 packet.ip.daddr = dest;
1206 packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
1207 if (check && check != checksum(&packet, bytes)) {
1208 DEBUG(LOG_ERR, "packet with bad UDP checksum received, ignoring");
1209 return -1;
1210 }
1211
1212 memcpy(payload, &(packet.data),
1213 bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
1214
1215 if (ntohl(payload->cookie) != DHCP_MAGIC) {
1216 LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring");
1217 return -1;
1218 }
1219 DEBUG(LOG_INFO, "oooooh!!! got some!");
1220 return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
1221}
1222
1223
1224int udhcpc_main(int argc, char *argv[])
1225{
1226 unsigned char *temp, *message;
1227 unsigned long t1 = 0, t2 = 0, xid = 0;
1228 unsigned long start = 0, lease;
1229 fd_set rfds;
1230 int retval;
1231 struct timeval tv;
1232 int c, len;
1233 struct dhcpMessage packet;
1234 struct in_addr temp_addr;
1235 int pid_fd;
1236 time_t now;
1237
1238 static struct option l_options[] = {
1239 {"clientid", required_argument, 0, 'c'},
1240 {"foreground", no_argument, 0, 'f'},
1241 {"hostname", required_argument, 0, 'H'},
1242 {"help", no_argument, 0, 'h'},
1243 {"interface", required_argument, 0, 'i'},
1244 {"now", no_argument, 0, 'n'},
1245 {"pidfile", required_argument, 0, 'p'},
1246 {"quit", no_argument, 0, 'q'},
1247 {"request", required_argument, 0, 'r'},
1248 {"script", required_argument, 0, 's'},
1249 {"version", no_argument, 0, 'v'},
1250 {0, 0, 0, 0}
1251 };
1252
1253 /* get options */
1254 while (1) {
1255 int option_index = 0;
1256
1257 c = getopt_long(argc, argv, "c:fH:i:np:qr:s:v", l_options,
1258 &option_index);
1259 if (c == -1) {
1260 break;
1261 }
1262
1263 switch (c) {
1264 case 'c':
1265 len = strlen(optarg);
1266 if (len > 255) {
1267 len = 255;
1268 }
1269 if (client_config.clientid) {
1270 free(client_config.clientid);
1271 }
1272 client_config.clientid = xmalloc(len + 2);
1273 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
1274 client_config.clientid[OPT_LEN] = len;
1275 client_config.clientid[OPT_DATA] = '\0';
1276 strncpy(client_config.clientid + 3, optarg, len - 1);
1277 break;
1278 case 'f':
1279 client_config.foreground = 1;
1280 break;
1281 case 'H':
1282 len = strlen(optarg);
1283 if (len > 255) {
1284 len = 255;
1285 }
1286 if (client_config.hostname) {
1287 free(client_config.hostname);
1288 }
1289 client_config.hostname = xmalloc(len + 2);
1290 client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
1291 client_config.hostname[OPT_LEN] = len;
1292 strncpy(client_config.hostname + 2, optarg, len);
1293 break;
1294 case 'i':
1295 client_config.interface = optarg;
1296 break;
1297 case 'n':
1298 client_config.abort_if_no_lease = 1;
1299 break;
1300 case 'p':
1301 client_config.pidfile = optarg;
1302 break;
1303 case 'q':
1304 client_config.quit_after_lease = 1;
1305 break;
1306 case 'r':
1307 requested_ip = inet_addr(optarg);
1308 break;
1309 case 's':
1310 client_config.script = optarg;
1311 break;
1312 case 'v':
1313 printf("udhcpcd, version %s\n\n", VERSION);
1314 exit_client(0);
1315 break;
1316 default:
1317 show_usage();
1318 }
1319 }
1320
1321 OPEN_LOG("udhcpc");
1322 LOG(LOG_INFO, "udhcp client (v%s) started", VERSION);
1323
1324 pid_fd = pidfile_acquire(client_config.pidfile);
1325 pidfile_write_release(pid_fd);
1326
1327 if (read_interface
1328 (client_config.interface, &client_config.ifindex, NULL,
1329 client_config.arp) < 0) {
1330 exit_client(1);
1331 }
1332
1333 if (!client_config.clientid) {
1334 client_config.clientid = xmalloc(6 + 3);
1335 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
1336 client_config.clientid[OPT_LEN] = 7;
1337 client_config.clientid[OPT_DATA] = 1;
1338 memcpy(client_config.clientid + 3, client_config.arp, 6);
1339 }
1340
1341 /* setup signal handlers */
1342 signal(SIGUSR1, renew_requested);
1343 signal(SIGUSR2, release_requested);
1344 signal(SIGTERM, terminate);
1345
1346 state = INIT_SELECTING;
1347 run_script(NULL, "deconfig");
1348 change_mode(LISTEN_RAW);
1349
1350 for (;;) {
1351 tv.tv_sec = timeout - time(0);
1352 tv.tv_usec = 0;
1353 FD_ZERO(&rfds);
1354
1355 if (listen_mode != LISTEN_NONE && fd_main < 0) {
1356 if (listen_mode == LISTEN_KERNEL) {
1357 fd_main =
1358 listen_socket(INADDR_ANY, CLIENT_PORT,
1359 client_config.interface);
1360 } else {
1361 fd_main = raw_socket(client_config.ifindex);
1362 }
1363 if (fd_main < 0) {
1364 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s",
1365 strerror(errno));
1366 exit_client(0);
1367 }
1368 }
1369 if (fd_main >= 0) {
1370 FD_SET(fd_main, &rfds);
1371 }
1372
1373 if (tv.tv_sec > 0) {
1374 DEBUG(LOG_INFO, "Waiting on select...\n");
1375 retval = select(fd_main + 1, &rfds, NULL, NULL, &tv);
1376 } else {
1377 retval = 0; /* If we already timed out, fall through */
1378 }
1379
1380 now = time(0);
1381 if (retval == 0) {
1382 /* timeout dropped to zero */
1383 switch (state) {
1384 case INIT_SELECTING:
1385 if (packet_num < 3) {
1386 if (packet_num == 0) {
1387 xid = random_xid();
1388 }
1389 /* send discover packet */
1390 send_discover(xid, requested_ip); /* broadcast */
1391
1392 timeout = now + ((packet_num == 2) ? 10 : 2);
1393 packet_num++;
1394 } else {
1395 if (client_config.abort_if_no_lease) {
1396 LOG(LOG_INFO, "No lease, failing.");
1397 exit_client(1);
1398 }
1399 /* wait to try again */
1400 packet_num = 0;
1401 timeout = now + 60;
1402 }
1403 break;
1404 case RENEW_REQUESTED:
1405 case REQUESTING:
1406 if (packet_num < 3) {
1407 /* send request packet */
1408 if (state == RENEW_REQUESTED) {
1409 send_renew(xid, server_addr, requested_ip); /* unicast */
1410 } else {
1411 send_selecting(xid, server_addr, requested_ip); /* broadcast */
1412 }
1413 timeout = now + ((packet_num == 2) ? 10 : 2);
1414 packet_num++;
1415 } else {
1416 /* timed out, go back to init state */
1417 state = INIT_SELECTING;
1418 timeout = now;
1419 packet_num = 0;
1420 change_mode(LISTEN_RAW);
1421 }
1422 break;
1423 case BOUND:
1424 /* Lease is starting to run out, time to enter renewing state */
1425 state = RENEWING;
1426 change_mode(LISTEN_KERNEL);
1427 DEBUG(LOG_INFO, "Entering renew state");
1428 /* fall right through */
1429 case RENEWING:
1430 /* Either set a new T1, or enter REBINDING state */
1431 if ((t2 - t1) <= (lease / 14400 + 1)) {
1432 /* timed out, enter rebinding state */
1433 state = REBINDING;
1434 timeout = now + (t2 - t1);
1435 DEBUG(LOG_INFO, "Entering rebinding state");
1436 } else {
1437 /* send a request packet */
1438 send_renew(xid, server_addr, requested_ip); /* unicast */
1439
1440 t1 = (t2 - t1) / 2 + t1;
1441 timeout = t1 + start;
1442 }
1443 break;
1444 case REBINDING:
1445 /* Either set a new T2, or enter INIT state */
1446 if ((lease - t2) <= (lease / 14400 + 1)) {
1447 /* timed out, enter init state */
1448 state = INIT_SELECTING;
1449 LOG(LOG_INFO, "Lease lost, entering init state");
1450 run_script(NULL, "deconfig");
1451 timeout = now;
1452 packet_num = 0;
1453 change_mode(LISTEN_RAW);
1454 } else {
1455 /* send a request packet */
1456 send_renew(xid, 0, requested_ip); /* broadcast */
1457
1458 t2 = (lease - t2) / 2 + t2;
1459 timeout = t2 + start;
1460 }
1461 break;
1462 case RELEASED:
1463 /* yah, I know, *you* say it would never happen */
1464 timeout = 0x7fffffff;
1465 break;
1466 }
1467 } else if (retval > 0 && listen_mode != LISTEN_NONE
1468 && FD_ISSET(fd_main, &rfds)) {
1469 /* a packet is ready, read it */
1470
1471 if (listen_mode == LISTEN_KERNEL) {
1472 len = get_packet(&packet, fd_main);
1473 } else {
1474 len = get_raw_packet(&packet, fd_main);
1475 }
1476 if (len == -1 && errno != EINTR) {
1477 DEBUG(LOG_INFO, "error on read, %s, reopening socket",
1478 strerror(errno));
1479 change_mode(listen_mode); /* just close and reopen */
1480 }
1481 if (len < 0) {
1482 continue;
1483 }
1484
1485 if (packet.xid != xid) {
1486 DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
1487 (unsigned long) packet.xid, xid);
1488 continue;
1489 }
1490
1491 if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
1492 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
1493 continue;
1494 }
1495
1496 switch (state) {
1497 case INIT_SELECTING:
1498 /* Must be a DHCPOFFER to one of our xid's */
1499 if (*message == DHCPOFFER) {
1500 if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
1501 memcpy(&server_addr, temp, 4);
1502 xid = packet.xid;
1503 requested_ip = packet.yiaddr;
1504
1505 /* enter requesting state */
1506 state = REQUESTING;
1507 timeout = now;
1508 packet_num = 0;
1509 } else {
1510 DEBUG(LOG_ERR, "No server ID in message");
1511 }
1512 }
1513 break;
1514 case RENEW_REQUESTED:
1515 case REQUESTING:
1516 case RENEWING:
1517 case REBINDING:
1518 if (*message == DHCPACK) {
1519 if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
1520 LOG(LOG_ERR,
1521 "No lease time with ACK, using 1 hour lease");
1522 lease = 60 * 60;
1523 } else {
1524 memcpy(&lease, temp, 4);
1525 lease = ntohl(lease);
1526 }
1527
1528 /* enter bound state */
1529 t1 = lease / 2;
1530
1531 /* little fixed point for n * .875 */
1532 t2 = (lease * 0x7) >> 3;
1533 temp_addr.s_addr = packet.yiaddr;
1534 LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
1535 inet_ntoa(temp_addr), lease);
1536 start = now;
1537 timeout = t1 + start;
1538 requested_ip = packet.yiaddr;
1539 run_script(&packet,
1540 ((state == RENEWING
1541 || state == REBINDING) ? "renew" : "bound"));
1542
1543 state = BOUND;
1544 change_mode(LISTEN_NONE);
1545 {
1546 int pid_fd2;
1547
1548 if (client_config.quit_after_lease) {
1549 exit_client(0);
1550 } else if (!client_config.foreground) {
1551 pid_fd2 = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
1552 if (daemon(0, 0) == -1) {
1553 perror("fork");
1554 exit_client(1);
1555 }
1556 client_config.foreground = 1; /* Do not fork again. */
1557 pidfile_write_release(pid_fd2);
1558 }
1559 }
1560 } else if (*message == DHCPNAK) {
1561 /* return to init state */
1562 LOG(LOG_INFO, "Received DHCP NAK");
1563 run_script(&packet, "nak");
1564 if (state != REQUESTING) {
1565 run_script(NULL, "deconfig");
1566 }
1567 state = INIT_SELECTING;
1568 timeout = now;
1569 requested_ip = 0;
1570 packet_num = 0;
1571 change_mode(LISTEN_RAW);
1572 sleep(3); /* avoid excessive network traffic */
1573 }
1574 break;
1575 /* case BOUND, RELEASED: - ignore all packets */
1576 }
1577 } else if (retval == -1 && errno == EINTR) {
1578 /* a signal was caught */
1579
1580 } else {
1581 /* An error occured */
1582 DEBUG(LOG_ERR, "Error on select");
1583 }
1584
1585 }
1586 return 0;
1587}