diff options
48 files changed, 4421 insertions, 1597 deletions
@@ -22,7 +22,7 @@ include $(TOPDIR).config | |||
22 | include $(TOPDIR)Rules.mak | 22 | include $(TOPDIR)Rules.mak |
23 | SUBDIRS:=applets archival archival/libunarchive console-tools \ | 23 | SUBDIRS:=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 | ||
28 | all: do-it-all | 28 | all: 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 | ||
4 | RESOLV_CONF="/etc/resolv.conf" | 4 | RESOLV_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 | |||
4 | echo 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 | ||
4 | RESOLV_CONF="/etc/resolv.conf" | 4 | RESOLV_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 | |||
27 | do | 27 | do |
28 | echo adding dns $i | 28 | echo adding dns $i |
29 | echo nameserver $i >> $RESOLV_CONF | 29 | echo nameserver $i >> $RESOLV_CONF |
30 | done | 30 | done \ 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 | ||
7 | exec /usr/share/udhcpc/default.$1 | 7 | exec /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 | |||
7 | RESOLV_CONF="/etc/resolv.conf" | ||
8 | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" | ||
9 | [ -n "$subnet" ] && NETMASK="netmask $subnet" | ||
10 | |||
11 | case "$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 | ;; | ||
37 | esac | ||
38 | |||
39 | exit 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 | |||
5 | start 192.168.0.20 #default: 192.168.0.20 | ||
6 | end 192.168.0.254 #default: 192.168.0.254 | ||
7 | |||
8 | |||
9 | # The interface that udhcpd will use | ||
10 | |||
11 | interface 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 | ||
86 | opt dns 192.168.10.2 192.168.10.10 | ||
87 | option subnet 255.255.255.0 | ||
88 | opt router 192.168.10.2 | ||
89 | opt wins 192.168.10.10 | ||
90 | option dns 129.219.13.81 # appened to above DNS servers for a total of 3 | ||
91 | option domain local | ||
92 | option 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 | |||
35 | NETWORKING-$(CONFIG_TELNETD) += telnetd.o | 35 | NETWORKING-$(CONFIG_TELNETD) += telnetd.o |
36 | NETWORKING-$(CONFIG_TFTP) += tftp.o | 36 | NETWORKING-$(CONFIG_TFTP) += tftp.o |
37 | NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o | 37 | NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o |
38 | NETWORKING-$(CONFIG_UDHCPC) += udhcpc.o | ||
39 | NETWORKING-$(CONFIG_WGET) += wget.o | 38 | NETWORKING-$(CONFIG_WGET) += wget.o |
40 | 39 | ||
41 | libraries-y+=$(NETWORKING_DIR)$(NETWORKING_AR) | 40 | libraries-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 |
49 | fi | 49 | fi |
50 | bool 'udhcpc' CONFIG_UDHCPC | ||
51 | bool 'wget' CONFIG_WGET | 50 | bool 'wget' CONFIG_WGET |
52 | if [ "$CONFIG_WGET" = "y" ]; then | 51 | if [ "$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 |
55 | fi | 54 | fi |
56 | 55 | ||
56 | source networking/udhcp/config.in | ||
57 | |||
57 | endmenu | 58 | endmenu |
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 @@ | |||
1 | udhcp server/client package | ||
2 | ----------------------- | ||
3 | |||
4 | Russ Dill <Russ.Dill@asu.edu> | ||
5 | Matthew Ramsay <matthewr@moreton.com.au> | ||
6 | Chris Trew <christ@moreton.com.au> | ||
7 | |||
8 | Other Credits: | ||
9 | -------------- | ||
10 | Moreton Bay (http://www.moretonbay.com/) | ||
11 | Lineo (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 | ||
12 | freedom to share and change it. By contrast, the GNU General Public | ||
13 | License is intended to guarantee your freedom to share and change free | ||
14 | software--to make sure the software is free for all its users. This | ||
15 | General Public License applies to most of the Free Software | ||
16 | Foundation's software and to any other program whose authors commit to | ||
17 | using it. (Some other Free Software Foundation software is covered by | ||
18 | the GNU Library General Public License instead.) You can apply it to | ||
19 | your programs, too. | ||
20 | |||
21 | When we speak of free software, we are referring to freedom, not | ||
22 | price. Our General Public Licenses are designed to make sure that you | ||
23 | have the freedom to distribute copies of free software (and charge for | ||
24 | this service if you wish), that you receive source code or can get it | ||
25 | if you want it, that you can change the software or use pieces of it | ||
26 | in 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 | ||
29 | anyone to deny you these rights or to ask you to surrender the rights. | ||
30 | These restrictions translate to certain responsibilities for you if you | ||
31 | distribute copies of the software, or if you modify it. | ||
32 | |||
33 | For example, if you distribute copies of such a program, whether | ||
34 | gratis or for a fee, you must give the recipients all the rights that | ||
35 | you have. You must make sure that they, too, receive or can get the | ||
36 | source code. And you must show them these terms so they know their | ||
37 | rights. | ||
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, | ||
41 | distribute and/or modify the software. | ||
42 | |||
43 | Also, for each author's protection and ours, we want to make certain | ||
44 | that everyone understands that there is no warranty for this free | ||
45 | software. If the software is modified by someone else and passed on, we | ||
46 | want its recipients to know that what they have is not the original, so | ||
47 | that any problems introduced by others will not reflect on the original | ||
48 | authors' reputations. | ||
49 | |||
50 | Finally, any free program is threatened constantly by software | ||
51 | patents. We wish to avoid the danger that redistributors of a free | ||
52 | program will individually obtain patent licenses, in effect making the | ||
53 | program proprietary. To prevent this, we have made it clear that any | ||
54 | patent must be licensed for everyone's free use or not licensed at all. | ||
55 | |||
56 | The precise terms and conditions for copying, distribution and | ||
57 | modification 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 | ||
63 | a notice placed by the copyright holder saying it may be distributed | ||
64 | under the terms of this General Public License. The "Program", below, | ||
65 | refers to any such program or work, and a "work based on the Program" | ||
66 | means either the Program or any derivative work under copyright law: | ||
67 | that is to say, a work containing the Program or a portion of it, | ||
68 | either verbatim or with modifications and/or translated into another | ||
69 | language. (Hereinafter, translation is included without limitation in | ||
70 | the term "modification".) Each licensee is addressed as "you". | ||
71 | |||
72 | Activities other than copying, distribution and modification are not | ||
73 | covered by this License; they are outside its scope. The act of | ||
74 | running the Program is not restricted, and the output from the Program | ||
75 | is covered only if its contents constitute a work based on the | ||
76 | Program (independent of having been made by running the Program). | ||
77 | Whether that is true depends on what the Program does. | ||
78 | |||
79 | 1. You may copy and distribute verbatim copies of the Program's | ||
80 | source code as you receive it, in any medium, provided that you | ||
81 | conspicuously and appropriately publish on each copy an appropriate | ||
82 | copyright notice and disclaimer of warranty; keep intact all the | ||
83 | notices that refer to this License and to the absence of any warranty; | ||
84 | and give any other recipients of the Program a copy of this License | ||
85 | along with the Program. | ||
86 | |||
87 | You may charge a fee for the physical act of transferring a copy, and | ||
88 | you 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 | ||
91 | of it, thus forming a work based on the Program, and copy and | ||
92 | distribute such modifications or work under the terms of Section 1 | ||
93 | above, 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 | |||
114 | These requirements apply to the modified work as a whole. If | ||
115 | identifiable sections of that work are not derived from the Program, | ||
116 | and can be reasonably considered independent and separate works in | ||
117 | themselves, then this License, and its terms, do not apply to those | ||
118 | sections when you distribute them as separate works. But when you | ||
119 | distribute the same sections as part of a whole which is a work based | ||
120 | on the Program, the distribution of the whole must be on the terms of | ||
121 | this License, whose permissions for other licensees extend to the | ||
122 | entire whole, and thus to each and every part regardless of who wrote it. | ||
123 | |||
124 | Thus, it is not the intent of this section to claim rights or contest | ||
125 | your rights to work written entirely by you; rather, the intent is to | ||
126 | exercise the right to control the distribution of derivative or | ||
127 | collective works based on the Program. | ||
128 | |||
129 | In addition, mere aggregation of another work not based on the Program | ||
130 | with the Program (or with a work based on the Program) on a volume of | ||
131 | a storage or distribution medium does not bring the other work under | ||
132 | the scope of this License. | ||
133 | |||
134 | 3. You may copy and distribute the Program (or a work based on it, | ||
135 | under Section 2) in object code or executable form under the terms of | ||
136 | Sections 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 | |||
155 | The source code for a work means the preferred form of the work for | ||
156 | making modifications to it. For an executable work, complete source | ||
157 | code means all the source code for all modules it contains, plus any | ||
158 | associated interface definition files, plus the scripts used to | ||
159 | control compilation and installation of the executable. However, as a | ||
160 | special exception, the source code distributed need not include | ||
161 | anything that is normally distributed (in either source or binary | ||
162 | form) with the major components (compiler, kernel, and so on) of the | ||
163 | operating system on which the executable runs, unless that component | ||
164 | itself accompanies the executable. | ||
165 | |||
166 | If distribution of executable or object code is made by offering | ||
167 | access to copy from a designated place, then offering equivalent | ||
168 | access to copy the source code from the same place counts as | ||
169 | distribution of the source code, even though third parties are not | ||
170 | compelled to copy the source along with the object code. | ||
171 | |||
172 | 4. You may not copy, modify, sublicense, or distribute the Program | ||
173 | except as expressly provided under this License. Any attempt | ||
174 | otherwise to copy, modify, sublicense or distribute the Program is | ||
175 | void, and will automatically terminate your rights under this License. | ||
176 | However, parties who have received copies, or rights, from you under | ||
177 | this License will not have their licenses terminated so long as such | ||
178 | parties remain in full compliance. | ||
179 | |||
180 | 5. You are not required to accept this License, since you have not | ||
181 | signed it. However, nothing else grants you permission to modify or | ||
182 | distribute the Program or its derivative works. These actions are | ||
183 | prohibited by law if you do not accept this License. Therefore, by | ||
184 | modifying or distributing the Program (or any work based on the | ||
185 | Program), you indicate your acceptance of this License to do so, and | ||
186 | all its terms and conditions for copying, distributing or modifying | ||
187 | the Program or works based on it. | ||
188 | |||
189 | 6. Each time you redistribute the Program (or any work based on the | ||
190 | Program), the recipient automatically receives a license from the | ||
191 | original licensor to copy, distribute or modify the Program subject to | ||
192 | these terms and conditions. You may not impose any further | ||
193 | restrictions on the recipients' exercise of the rights granted herein. | ||
194 | You are not responsible for enforcing compliance by third parties to | ||
195 | this License. | ||
196 | |||
197 | 7. If, as a consequence of a court judgment or allegation of patent | ||
198 | infringement or for any other reason (not limited to patent issues), | ||
199 | conditions are imposed on you (whether by court order, agreement or | ||
200 | otherwise) that contradict the conditions of this License, they do not | ||
201 | excuse you from the conditions of this License. If you cannot | ||
202 | distribute so as to satisfy simultaneously your obligations under this | ||
203 | License and any other pertinent obligations, then as a consequence you | ||
204 | may not distribute the Program at all. For example, if a patent | ||
205 | license would not permit royalty-free redistribution of the Program by | ||
206 | all those who receive copies directly or indirectly through you, then | ||
207 | the only way you could satisfy both it and this License would be to | ||
208 | refrain entirely from distribution of the Program. | ||
209 | |||
210 | If any portion of this section is held invalid or unenforceable under | ||
211 | any particular circumstance, the balance of the section is intended to | ||
212 | apply and the section as a whole is intended to apply in other | ||
213 | circumstances. | ||
214 | |||
215 | It is not the purpose of this section to induce you to infringe any | ||
216 | patents or other property right claims or to contest validity of any | ||
217 | such claims; this section has the sole purpose of protecting the | ||
218 | integrity of the free software distribution system, which is | ||
219 | implemented by public license practices. Many people have made | ||
220 | generous contributions to the wide range of software distributed | ||
221 | through that system in reliance on consistent application of that | ||
222 | system; it is up to the author/donor to decide if he or she is willing | ||
223 | to distribute software through any other system and a licensee cannot | ||
224 | impose that choice. | ||
225 | |||
226 | This section is intended to make thoroughly clear what is believed to | ||
227 | be a consequence of the rest of this License. | ||
228 | |||
229 | 8. If the distribution and/or use of the Program is restricted in | ||
230 | certain countries either by patents or by copyrighted interfaces, the | ||
231 | original copyright holder who places the Program under this License | ||
232 | may add an explicit geographical distribution limitation excluding | ||
233 | those countries, so that distribution is permitted only in or among | ||
234 | countries not thus excluded. In such case, this License incorporates | ||
235 | the limitation as if written in the body of this License. | ||
236 | |||
237 | 9. The Free Software Foundation may publish revised and/or new versions | ||
238 | of the General Public License from time to time. Such new versions will | ||
239 | be similar in spirit to the present version, but may differ in detail to | ||
240 | address new problems or concerns. | ||
241 | |||
242 | Each version is given a distinguishing version number. If the Program | ||
243 | specifies a version number of this License which applies to it and "any | ||
244 | later version", you have the option of following the terms and conditions | ||
245 | either of that version or of any later version published by the Free | ||
246 | Software Foundation. If the Program does not specify a version number of | ||
247 | this License, you may choose any version ever published by the Free Software | ||
248 | Foundation. | ||
249 | |||
250 | 10. If you wish to incorporate parts of the Program into other free | ||
251 | programs whose distribution conditions are different, write to the author | ||
252 | to ask for permission. For software which is copyrighted by the Free | ||
253 | Software Foundation, write to the Free Software Foundation; we sometimes | ||
254 | make exceptions for this. Our decision will be guided by the two goals | ||
255 | of preserving the free status of all derivatives of our free software and | ||
256 | of 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 | ||
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | ||
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | ||
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | ||
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||
268 | REPAIR OR CORRECTION. | ||
269 | |||
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||
278 | POSSIBILITY 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 | ||
285 | possible use to the public, the best way to achieve this is to make it | ||
286 | free 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 | ||
289 | to attach them to the start of each source file to most effectively | ||
290 | convey the exclusion of warranty; and each file should have at least | ||
291 | the "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 | |||
310 | Also add information on how to contact you by electronic and paper mail. | ||
311 | |||
312 | If the program is interactive, make it output a short notice like this | ||
313 | when 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 | |||
320 | The hypothetical commands `show w' and `show c' should show the appropriate | ||
321 | parts of the General Public License. Of course, the commands you use may | ||
322 | be called something other than `show w' and `show c'; they could even be | ||
323 | mouse-clicks or menu items--whatever suits your program. | ||
324 | |||
325 | You should also get your employer (if you work as a programmer) or your | ||
326 | school, if any, to sign a "copyright disclaimer" for the program, if | ||
327 | necessary. 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 | |||
335 | This General Public License does not permit incorporating your program into | ||
336 | proprietary programs. If your program is a subroutine library, you may | ||
337 | consider it more useful to permit linking proprietary applications with the | ||
338 | library. If this is what you want to do, use the GNU Library General | ||
339 | Public 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 @@ | |||
1 | 0.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 | |||
31 | 0.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 | |||
58 | 0.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 | |||
65 | 0.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 | |||
71 | 0.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 | |||
79 | 0.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 | |||
87 | 0.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 | |||
95 | 0.9.1 (010806) | ||
96 | + Added udhcpc client | ||
97 | + reorganized functions/files | ||
98 | + listening socket now only binds to one interface | ||
99 | |||
100 | 0.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 | |||
114 | 0.8.29 (000323) | ||
115 | + stable(?) release | ||
116 | |||
117 | |||
118 | 0.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 | |||
124 | 0.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 | |||
129 | 0.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 | |||
134 | 0.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 | |||
139 | 0.8.23 (000117) | ||
140 | + NETtel specific fix for ignoring dhcp requests on 2nd interface | ||
141 | |||
142 | 0.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 | |||
147 | 0.8.21 (000113) | ||
148 | + now sends the correct server ip instead of hardcoded value | ||
149 | + minor debugging fixes for critical messages | ||
150 | |||
151 | 0.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 | |||
159 | 0.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 | |||
163 | 0.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 | |||
169 | 0.8.17 (991212) | ||
170 | |||
171 | - has problems clearing out the offered array | ||
172 | |||
173 | 0.8.16 (991203) | ||
174 | + Non blocking error is changes to informational as it is not really | ||
175 | an error | ||
176 | |||
177 | 0.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 | |||
181 | 0.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 | |||
186 | 0.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 | |||
192 | 0.8.12 (991111) | ||
193 | + debugging was real bad.. cleaned up a bit.. needs overhaul | ||
194 | |||
195 | |||
196 | 0.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 | |||
208 | 0.8.10 (991105) | ||
209 | + \n bug in arpping | ||
210 | + minor debugging changes (removed printfs etc) | ||
211 | + started browseiplist (not finished) | ||
212 | |||
213 | 0.8.9 (19991105) | ||
214 | + fixed options array size bug (options were cut off) | ||
215 | |||
216 | 0.8.8 (19991105) | ||
217 | + ignores requests from dhcpcd on the same machine | ||
218 | |||
219 | 0.8.7 (19991104) | ||
220 | + don't die if we can't bind to search for existing DHCP server | ||
221 | + slightly more verbose syslogging | ||
222 | |||
223 | 0.8.6 (19991103) | ||
224 | + added makeiplist (not finished -- core dumps) | ||
225 | + minor debug changes | ||
226 | |||
227 | 0.8.5 (19991029) | ||
228 | + exits if another DHCP server is already on the network | ||
229 | + added Linux Makefile | ||
230 | |||
231 | 0.8.4 (19991026) | ||
232 | + minor bug fix in findaddr preventing an addr being found | ||
233 | |||
234 | 0.8.3 (19991025) | ||
235 | + fixed up debugging | ||
236 | + minor hwaddr issues | ||
237 | |||
238 | 0.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 | |||
20 | UDHCP_AR:=udhcp.a | ||
21 | ifndef $(UDHCP_DIR) | ||
22 | UDHCP_DIR:=$(TOPDIR)networking/udhcp/ | ||
23 | endif | ||
24 | |||
25 | #ok, so I forgot how to do an or, but this is a quick and dirty hack | ||
26 | ifeq ($(CONFIG_UDHCPC), y) | ||
27 | CONFIG_UDHCP_SHARED=y | ||
28 | else | ||
29 | ifeq ($(CONFIG_UDHCPD), y) | ||
30 | CONFIG_UDHCP_SHARED=y | ||
31 | else | ||
32 | CONFIG_UDHCP_SHARED=n | ||
33 | endif | ||
34 | endif | ||
35 | |||
36 | UDHCP-y:= | ||
37 | UDHCP-$(CONFIG_UDHCP_SHARED) += options.o socket.o packet.o pidfile.o | ||
38 | UDHCP-$(CONFIG_UDHCPC) += dhcpc.o clientpacket.o script.o | ||
39 | UDHCP-$(CONFIG_UDHCPD) += dhcpd.o arpping.o files.o leases.o serverpacket.o | ||
40 | UDHCP-$(CONFIG_DUMPLEASES) += dumpleases.o | ||
41 | |||
42 | libraries-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 @@ | |||
1 | udhcp server/client package readme | ||
2 | ------------------------- | ||
3 | |||
4 | The udhcp server/client package is primarily geared towards embedded | ||
5 | systems. It does however, strive to be fully functional, and RFC | ||
6 | compliant. | ||
7 | |||
8 | udhcp server (udhcpd) | ||
9 | -------------------- | ||
10 | |||
11 | The only command line argument to udhcpd is an optional specifed | ||
12 | config file. If no config file is specified, udhcpd uses the default | ||
13 | config file, /etc/udhcpd.conf. Ex: | ||
14 | |||
15 | udhcpd /etc/udhcpd.eth1.conf | ||
16 | |||
17 | The udhcp server employs a number of simple config files: | ||
18 | |||
19 | udhcpd.leases | ||
20 | ------------ | ||
21 | |||
22 | The udhcpd.leases behavior is designed for an embedded system. The | ||
23 | file is written either every auto_time seconds, or when a SIGUSR1 | ||
24 | is received (the auto_time timer restarts if a SIGUSR1 is received). | ||
25 | If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will | ||
26 | finish writing the leases file and wait for the aftermentioned script | ||
27 | to be executed and finish before quiting, so you do not need to sleep | ||
28 | between sending signals. When the file is written, a script can be | ||
29 | optionally called to commit the file to flash. Lease times are stored | ||
30 | in the file by time remaining in lease (for systems without clock | ||
31 | that works when there is no power), or by the absolute time that it | ||
32 | expires in seconds from epoch. In the remainig format, expired leases | ||
33 | are stored as zero. The file is of the format: | ||
34 | |||
35 | 16 byte MAC | ||
36 | 4 byte ip address | ||
37 | u32 expire time | ||
38 | 16 byte MAC | ||
39 | 4 byte ip address | ||
40 | u32 expire time | ||
41 | . | ||
42 | etc. | ||
43 | |||
44 | example: hexdump udhcpd.leases | ||
45 | |||
46 | 0000000 1000 c95a 27d9 0000 0000 0000 0000 0000 | ||
47 | 0000010 a8c0 150a 0d00 2d29 5000 23fc 8566 0000 | ||
48 | 0000020 0000 0000 0000 0000 a8c0 140a 0d00 4e29 | ||
49 | 0000030 | ||
50 | |||
51 | |||
52 | udhcpd.conf | ||
53 | ---------- | ||
54 | |||
55 | The format is fairly simple, there is a sample file with all the | ||
56 | available options and comments describing them in samples/udhcpd.conf | ||
57 | |||
58 | |||
59 | udhcp client (udhcpc) | ||
60 | -------------------- | ||
61 | |||
62 | The udhcp client negotiates a lease with the DHCP server and notifies | ||
63 | a set of scripts when a leases is obtained or lost. The command line | ||
64 | options 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 | |||
82 | If the requested IP address cannot be obtained, the client accepts the | ||
83 | address that the server offers. | ||
84 | |||
85 | When an event occurs, udhcpc calls the action script. The script by | ||
86 | default is /usr/share/udhcpc/default.script but this can be changed via | ||
87 | the command line arguments. The three possible arguments to the script | ||
88 | are: | ||
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 | |||
112 | The 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 | |||
148 | additional options are easily added in options.c. | ||
149 | |||
150 | udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state, | ||
151 | and SIGUSR2 will force a release of the current lease, and cause udhcpc to | ||
152 | go into an inactive state (until it is killed, or receives a SIGUSR1). You do | ||
153 | not need to sleep between sending signals, as signals received are processed | ||
154 | sequencially in the order they are received. | ||
155 | |||
156 | |||
157 | |||
158 | compile time options | ||
159 | ------------------- | ||
160 | |||
161 | The 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 | |||
172 | dhcpd.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 | |||
179 | options.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 | |||
188 | busybox drop-in | ||
189 | -------------- | ||
190 | udhcp is now a drop-in component for busybox (http://busybox.net). | ||
191 | To update busybox to the latest revision, simply do a: | ||
192 | |||
193 | cp *.[ch] README AUTHORS COPYING ChangeLog TODO \ | ||
194 | <busybox_source>/networking/udhcp | ||
195 | |||
196 | The only two files udhcp does not provide are config.in and | ||
197 | Makefile.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 @@ | |||
1 | TODO | ||
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 */ | ||
35 | int 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 | |||
13 | struct 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 */ | ||
28 | int 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 */ | ||
48 | unsigned 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 */ | ||
60 | static 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. */ | ||
78 | static 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 */ | ||
94 | int 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 */ | ||
111 | int 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 */ | ||
131 | int 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 */ | ||
151 | int 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 */ | ||
168 | int 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 | |||
4 | unsigned long random_xid(void); | ||
5 | int send_discover(unsigned long xid, unsigned long requested); | ||
6 | int send_selecting(unsigned long xid, unsigned long server, unsigned long requested); | ||
7 | int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr); | ||
8 | int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr); | ||
9 | int send_release(unsigned long server, unsigned long ciaddr); | ||
10 | int 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 | |||
6 | mainmenu_option next_comment | ||
7 | comment 'udhcp Server/Client' | ||
8 | |||
9 | bool 'udhcp Server (udhcpd)' CONFIG_UDHCPD | ||
10 | bool 'udhcp Client (udhcpc)' CONFIG_UDHCPC | ||
11 | bool 'Lease display utility (dumpleases)' CONFIG_DUMPLEASES | ||
12 | if [ "$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 | ||
15 | fi | ||
16 | |||
17 | endmenu | ||
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 | |||
49 | static int state; | ||
50 | static unsigned long requested_ip; /* = 0 */ | ||
51 | static unsigned long server_addr; | ||
52 | static unsigned long timeout; | ||
53 | static int packet_num; /* = 0 */ | ||
54 | static int fd; | ||
55 | static int signal_pipe[2]; | ||
56 | |||
57 | #define LISTEN_NONE 0 | ||
58 | #define LISTEN_KERNEL 1 | ||
59 | #define LISTEN_RAW 2 | ||
60 | static int listen_mode; | ||
61 | |||
62 | #define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script" | ||
63 | |||
64 | struct 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 | ||
80 | static 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 */ | ||
106 | static 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 */ | ||
117 | static 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 */ | ||
146 | static 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 */ | ||
170 | static void exit_client(int retval) | ||
171 | { | ||
172 | pidfile_delete(client_config.pidfile); | ||
173 | CLOSE_LOG(); | ||
174 | exit(retval); | ||
175 | } | ||
176 | |||
177 | |||
178 | /* Signal handler */ | ||
179 | static 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 | |||
188 | static 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 | ||
204 | int udhcpc_main(int argc, char *argv[]) | ||
205 | #else | ||
206 | int 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 | |||
17 | struct 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 | |||
31 | extern 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 */ | ||
55 | struct dhcpOfferedAddr *leases; | ||
56 | struct server_config_t server_config; | ||
57 | static int signal_pipe[2]; | ||
58 | |||
59 | /* Exit and cleanup */ | ||
60 | static void exit_server(int retval) | ||
61 | { | ||
62 | pidfile_delete(server_config.pidfile); | ||
63 | CLOSE_LOG(); | ||
64 | exit(retval); | ||
65 | } | ||
66 | |||
67 | |||
68 | /* Signal handler */ | ||
69 | static 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 | ||
79 | int udhcpd_main(int argc, char *argv[]) | ||
80 | #else | ||
81 | int 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 | |||
95 | struct option_set { | ||
96 | unsigned char *data; | ||
97 | struct option_set *next; | ||
98 | }; | ||
99 | |||
100 | struct 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 | |||
127 | extern struct server_config_t server_config; | ||
128 | extern 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 | |||
25 | struct lease_t { | ||
26 | unsigned char chaddr[16]; | ||
27 | u_int32_t yiaddr; | ||
28 | u_int32_t expires; | ||
29 | }; | ||
30 | |||
31 | #ifdef BB_VER | ||
32 | int dumpleases_main(int argc, char *argv[]) | ||
33 | #else | ||
34 | int 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 */ | ||
22 | static 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 | |||
37 | static 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 | |||
48 | static 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 | |||
57 | static 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 */ | ||
73 | static 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 | |||
152 | static 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 | |||
177 | int 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 | |||
222 | void 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 | |||
257 | void 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 | |||
5 | struct config_keyword { | ||
6 | char keyword[14]; | ||
7 | int (*handler)(char *line, void *var); | ||
8 | void *var; | ||
9 | char def[30]; | ||
10 | }; | ||
11 | |||
12 | |||
13 | int read_config(char *file); | ||
14 | void write_leases(void); | ||
15 | void 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 | |||
3 | extern int udhcpd_main(int argc, char *argv[]); | ||
4 | extern int udhcpc_main(int argc, char *argv[]); | ||
5 | |||
6 | int 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 | |||
19 | unsigned char blank_chaddr[] = {[0 ... 15] = 0}; | ||
20 | |||
21 | /* clear every lease out that chaddr OR yiaddr matches and is nonzero */ | ||
22 | void 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 */ | ||
37 | struct 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 */ | ||
57 | int 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 */ | ||
64 | struct 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 */ | ||
82 | struct 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 */ | ||
94 | struct 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... */ | ||
107 | u_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 */ | ||
139 | int 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 | |||
6 | struct dhcpOfferedAddr { | ||
7 | u_int8_t chaddr[16]; | ||
8 | u_int32_t yiaddr; /* network order */ | ||
9 | u_int32_t expires; /* host order */ | ||
10 | }; | ||
11 | |||
12 | extern unsigned char blank_chaddr[]; | ||
13 | |||
14 | void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr); | ||
15 | struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease); | ||
16 | int lease_expired(struct dhcpOfferedAddr *lease); | ||
17 | struct dhcpOfferedAddr *oldest_expired_lease(void); | ||
18 | struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr); | ||
19 | struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr); | ||
20 | u_int32_t find_address(int check_expired); | ||
21 | int 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 */ | ||
18 | struct 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 */ | ||
50 | int 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). */ | ||
64 | unsigned 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) */ | ||
119 | int 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) */ | ||
133 | int 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 */ | ||
150 | int 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 */ | ||
187 | struct 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 */ | ||
198 | void 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 | |||
9 | enum { | ||
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 | |||
24 | struct dhcp_option { | ||
25 | char name[10]; | ||
26 | char flags; | ||
27 | unsigned char code; | ||
28 | }; | ||
29 | |||
30 | extern struct dhcp_option options[]; | ||
31 | extern int option_lengths[]; | ||
32 | |||
33 | unsigned char *get_option(struct dhcpMessage *packet, int code); | ||
34 | int end_option(unsigned char *optionptr); | ||
35 | int add_option_string(unsigned char *optionptr, unsigned char *string); | ||
36 | int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data); | ||
37 | struct option_set *find_option(struct option_set *opt_list, char code); | ||
38 | void 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 | |||
23 | void 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 */ | ||
47 | int 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 | |||
86 | u_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 */ | ||
117 | int 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 */ | ||
170 | int 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 | |||
7 | struct 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 | |||
26 | struct udp_dhcp_packet { | ||
27 | struct iphdr ip; | ||
28 | struct udphdr udp; | ||
29 | struct dhcpMessage data; | ||
30 | }; | ||
31 | |||
32 | void init_header(struct dhcpMessage *packet, char type); | ||
33 | int get_packet(struct dhcpMessage *packet, int fd); | ||
34 | u_int16_t checksum(void *addr, int count); | ||
35 | int 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); | ||
37 | int 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 | |||
32 | int 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 | |||
49 | void 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 | |||
64 | void 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 | |||
23 | int pidfile_acquire(char *pidfile); | ||
24 | void pidfile_write_release(int pid_fd); | ||
25 | void 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...) */ | ||
41 | static 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 | |||
54 | static 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 | |||
61 | static 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'. */ | ||
67 | static 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 | |||
124 | static 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 */ | ||
139 | static 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 */ | ||
202 | void 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 | |||
4 | void 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 */ | ||
35 | static 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 */ | ||
45 | static 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 */ | ||
73 | static 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 | |||
84 | static 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 */ | ||
97 | static 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 */ | ||
108 | int 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 | |||
189 | int 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 | |||
200 | int 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 | |||
243 | int 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 | |||
5 | int sendOffer(struct dhcpMessage *oldpacket); | ||
6 | int sendNAK(struct dhcpMessage *oldpacket); | ||
7 | int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr); | ||
8 | int 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 | |||
46 | int 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 | |||
93 | int 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 | |||
135 | int 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 | |||
5 | int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp); | ||
6 | int listen_socket(unsigned int ip, int port, char *inf); | ||
7 | int 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 | |||
55 | static int state; | ||
56 | static unsigned long requested_ip; /* = 0 */ | ||
57 | static unsigned long server_addr; | ||
58 | static unsigned long timeout; | ||
59 | static int packet_num; /* = 0 */ | ||
60 | static 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 | ||
69 | static 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 | |||
151 | enum { | ||
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 | |||
193 | struct 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 | |||
212 | struct 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 | |||
225 | struct 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 | |||
239 | struct dhcp_option { | ||
240 | char name[10]; | ||
241 | char flags; | ||
242 | unsigned char code; | ||
243 | }; | ||
244 | |||
245 | struct udp_dhcp_packet { | ||
246 | struct iphdr ip; | ||
247 | struct udphdr udp; | ||
248 | struct dhcpMessage data; | ||
249 | }; | ||
250 | |||
251 | static 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 */ | ||
283 | static 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...) */ | ||
296 | static 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) */ | ||
309 | static 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) */ | ||
324 | static 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 */ | ||
341 | static 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 | |||
385 | static 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 */ | ||
413 | static 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 */ | ||
468 | static 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 */ | ||
510 | static 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. */ | ||
550 | static 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 */ | ||
567 | static 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 */ | ||
583 | static 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 */ | ||
604 | static 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 */ | ||
624 | static 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 */ | ||
636 | static 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) */ | ||
647 | static 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). */ | ||
668 | static 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 | |||
723 | static 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'. */ | ||
730 | static 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 | |||
789 | static 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 */ | ||
804 | static 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 */ | ||
880 | static 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) */ | ||
909 | static 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 | |||
936 | static 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 | |||
955 | static 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 */ | ||
971 | static 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 */ | ||
983 | static void terminate(int sig) | ||
984 | { | ||
985 | sig = 0; | ||
986 | LOG(LOG_INFO, "Received SIGTERM"); | ||
987 | exit_client(0); | ||
988 | } | ||
989 | |||
990 | |||
991 | static 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 | |||
1040 | static 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 | |||
1086 | static 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 */ | ||
1111 | static 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 | |||
1150 | static 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 | |||
1224 | int 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 | } | ||