├── Makefile ├── gentoo ├── conf.d │ └── pxe-pdhcp └── init.d │ └── pxe-pdhcp ├── README.md ├── pdhcp.h ├── pdhcp.c ├── dhcp.h └── pxe-pdhcp.c /Makefile: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT = pxe-pdhcp 3 | 4 | CFLAGS += -Wall -g -O4 5 | 6 | SRCS = pdhcp.c pxe-pdhcp.c 7 | 8 | OBJS = $(subst .c,.o,$(SRCS)) 9 | 10 | .c.o: 11 | $(CC) $(CFLAGS) -c $< -o $@ 12 | 13 | $(OUTPUT): $(OBJS) 14 | $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ 15 | 16 | clean: 17 | rm -f $(OBJS) $(OUTPUT) 18 | 19 | 20 | .PHONY: source distclean 21 | source: 22 | distclean: clean 23 | -------------------------------------------------------------------------------- /gentoo/conf.d/pxe-pdhcp: -------------------------------------------------------------------------------- 1 | # pxe-pdhcp configuration script for Gentoo Linux. 2 | # written by int128 3 | # 4 | # pxe-pdhcp is an implementation of Preboot Execution Environment (PXE) server. 5 | 6 | PXE_EXEC="$(which pxe-pdhcp)" 7 | 8 | # TFTP server address. 9 | # pxe-pdhcp tells TFTP server adress to clients. 10 | PXE_TFTP_ADDRESS='192.168.1.100' 11 | 12 | # Boot-image path on TFTP server. 13 | # Clients will download boot-image from TFTP server. 14 | # 15 | # Example: 16 | #PXE_TFTP_IMAGE='syslinux.0' 17 | PXE_TFTP_IMAGE='undionly.kpxe' 18 | 19 | -------------------------------------------------------------------------------- /gentoo/init.d/pxe-pdhcp: -------------------------------------------------------------------------------- 1 | #!/sbin/runscript 2 | # pxe-pdhcp init script for Gentoo Linux. 3 | # written by int128 4 | # 5 | # pxe-pdhcp is an implementation of Preboot Execution Environment (PXE) server. 6 | 7 | depend() { 8 | need net 9 | } 10 | 11 | start() { 12 | ebegin "Starting ${SVCNAME}" 13 | start-stop-daemon --start --exec "${PXE_EXEC}" --pidfile "/var/run/${SVCNAME}.pid" \ 14 | -- \ 15 | -l '0.0.0.0' -b '255.255.255.255' \ 16 | -t "${PXE_TFTP_ADDRESS}" "${PXE_TFTP_IMAGE}" 17 | eend $? 18 | } 19 | 20 | stop() { 21 | ebegin "Stopping ${SVCNAME}" 22 | start-stop-daemon --stop --exec "${PXE_EXEC}" --pidfile "/var/run/${SVCNAME}.pid" 23 | eend $? 24 | } 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pxe-pdhcp 2 | =========== 3 | 4 | A implementation of Preboot Execution Environment (PXE) server. 5 | 6 | pxe-pdhcp works with DHCP server running on another host. The DHCP server 7 | doesn't need to be configured for any PXE specific options. This means that 8 | you can set up network boot environment without re-configuring existent DHCP 9 | server. 10 | 11 | usage: pxe-pdhcp [-d] [-i interface] 12 | [-l listen address] [-t tftp address] [-b broadcast address] 13 | 14 | 15 | pxe-pdhcp listens on two well-known ports (67/udp and 68/udp) so the root 16 | privilege is needed to run. 17 | 18 | With -d option, pxe-pdhcp runs on foreground. This option is useful for debugging. 19 | 20 | Specify nework interface name ('eth0' for example, on Linux) to -i option. 21 | 22 | If the network interface has more than one IP address, use -l, -t, -b options. 23 | -i or (-l,-t and -b) option is required. 24 | 25 | Finally specify the path of Network Bootstrap Program on the TFTP server to 26 | option. It will be 'pxelinux.0' if you are using PXELINUX. 27 | 28 | ---- 29 | 30 | Copyright (c) 2007-2016 Sadayuki Furuhashi 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in 40 | all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | THE SOFTWARE. 49 | 50 | dhcp.h is provided by ISC-DHCP copyright by Internet Systems Consortium 51 | licensed under MIT license. the original software and related information is 52 | available at https://www.isc.org/software/dhcp/. 53 | 54 | -------------------------------------------------------------------------------- /pdhcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pxe-pdhcp 3 | * 4 | * Copyright (c) 2007-2016 Sadayuki Furuhashi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef PXE_PDHCP_H 26 | #define PXE_PDHCP_H 1 27 | 28 | #include 29 | #include 30 | #include "dhcp.h" 31 | 32 | #define DHCP_SERVER_PORT 67 33 | #define DHCP_CLIENT_PORT 68 34 | 35 | #define DHCP_OPTIONS_COOKIE_LEN 4 36 | 37 | #define PXE_IDENTIFIER_STRING "PXEClient" 38 | 39 | #define PXE_MTFTP_IP 1 40 | #define PXE_MTFTP_CPORT 2 41 | #define PXE_MTFTP_SPORT 3 42 | #define PXE_MTFTP_TMOUT 4 43 | #define PXE_MTFTP_DELAY 5 44 | #define PXE_DISCOVERY_CONTROL 6 45 | #define PXE_DISCOVERY_MCAST_ADDR 7 46 | #define PXE_BOOT_SERVERS 8 47 | #define PXE_BOOT_MENU 9 48 | #define PXE_MENU_PROMPT 10 49 | #define PXE_MCAST_ADDRS_ALLOC 11 50 | #define PXE_CREDENTIAL_TYPES 12 51 | #define PXE_END 255 52 | 53 | #define PXE_DISCOVERY_CONTROL_BIT0 0x01 54 | #define PXE_DISCOVERY_CONTROL_BIT1 0x02 55 | #define PXE_DISCOVERY_CONTROL_BIT2 0x04 56 | #define PXE_DISCOVERY_CONTROL_BIT3 0x08 57 | 58 | int check_dhcp_packet(struct dhcp_packet *p); 59 | int get_dhcp_option(struct dhcp_packet *p, u_char type, 60 | u_char **opt, u_char *optlen); 61 | int get_dhcp_message_type(struct dhcp_packet *p); 62 | int get_dhcp_packet_len(struct dhcp_packet *p); 63 | int add_dhcp_option(struct dhcp_packet *p, u_char type, 64 | u_char *opt, u_char optlen); 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /pdhcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pxe-pdhcp 3 | * 4 | * Copyright (c) 2007-2016 Sadayuki Furuhashi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include "pdhcp.h" 29 | #include "dhcp.h" 30 | 31 | 32 | int check_dhcp_packet(struct dhcp_packet *p) 33 | { 34 | u_char *op; 35 | 36 | /* check magic cookie */ 37 | if (memcmp(p->options, DHCP_OPTIONS_COOKIE, DHCP_OPTIONS_COOKIE_LEN)) 38 | return -1; 39 | 40 | /* */ 41 | if (p->op != BOOTREQUEST) 42 | return -1; 43 | 44 | /* check packet length */ 45 | op = p->options + DHCP_OPTIONS_COOKIE_LEN; 46 | while (*op != DHO_END) { 47 | if (op - p->options >= DHCP_OPTION_LEN) 48 | return -1; 49 | else if (*op == DHO_PAD) 50 | ++op; 51 | else 52 | op += op[1] + 2; 53 | } 54 | return 0; 55 | } 56 | 57 | int get_dhcp_option(struct dhcp_packet *p, u_char type, u_char **opt, u_char *optlen) 58 | { 59 | u_char *opos = p->options + DHCP_OPTIONS_COOKIE_LEN; 60 | while (*opos != DHO_END) { 61 | if (*opos == type) { 62 | *opt = &opos[2]; 63 | *optlen = opos[1]; 64 | return 0; 65 | } 66 | if (*opos == DHO_PAD) 67 | opos++; 68 | else 69 | opos += opos[1] + 2; 70 | } 71 | return -1; 72 | } 73 | 74 | int get_dhcp_message_type(struct dhcp_packet *p) 75 | { 76 | u_char *opt, optlen; 77 | if (get_dhcp_option(p, DHO_DHCP_MESSAGE_TYPE, &opt, &optlen) == -1) { 78 | return -1; 79 | } 80 | return *opt; 81 | } 82 | 83 | int get_dhcp_packet_len(struct dhcp_packet *p) 84 | { 85 | u_char *op = p->options; 86 | op += DHCP_OPTIONS_COOKIE_LEN; 87 | while (*op != DHO_END) { 88 | if (*op == DHO_PAD) 89 | op++; 90 | else 91 | op += op[1] + 2; 92 | } 93 | return (op - (u_char*)p) + 1; 94 | } 95 | 96 | int add_dhcp_option(struct dhcp_packet *p, u_char type, 97 | u_char *opt, u_char optlen) 98 | { 99 | u_char *op; 100 | 101 | int len = get_dhcp_packet_len(p); 102 | if (len == -1) return -1; 103 | 104 | /* check if there is enough space left */ 105 | if (len + optlen + 3 > sizeof(struct dhcp_packet)) 106 | return -1; 107 | 108 | /* add new option */ 109 | op = (u_char*)p + len - 1; 110 | op[0] = type; 111 | op[1] = optlen; 112 | memcpy(&op[2], opt, optlen); 113 | 114 | /* and end marker */ 115 | op[2+optlen] = DHO_END; 116 | 117 | return 0; 118 | } 119 | 120 | -------------------------------------------------------------------------------- /dhcp.h: -------------------------------------------------------------------------------- 1 | /* dhcp.h 2 | 3 | Protocol structures... */ 4 | 5 | /* 6 | * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") 7 | * Copyright (c) 1995-2003 by Internet Software Consortium 8 | * 9 | * Permission to use, copy, modify, and distribute this software for any 10 | * purpose with or without fee is hereby granted, provided that the above 11 | * copyright notice and this permission notice appear in all copies. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | * 21 | * Internet Systems Consortium, Inc. 22 | * 950 Charter Street 23 | * Redwood City, CA 94063 24 | * 25 | * http://www.isc.org/ 26 | * 27 | * This software has been written for Internet Systems Consortium 28 | * by Ted Lemon in cooperation with Vixie Enterprises. To learn more 29 | * about Internet Systems Consortium, see ``http://www.isc.org''. 30 | * To learn more about Vixie Enterprises, see ``http://www.vix.com''. 31 | */ 32 | 33 | #ifndef DHCP_H 34 | #define DHCP_H 35 | 36 | #define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ 37 | 8) /* UDP header */ 38 | #define DHCP_SNAME_LEN 64 39 | #define DHCP_FILE_LEN 128 40 | #define DHCP_FIXED_NON_UDP 236 41 | #define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) 42 | /* Everything but options. */ 43 | #define DHCP_MTU_MAX 1500 44 | #define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN) 45 | 46 | #define BOOTP_MIN_LEN 300 47 | #define DHCP_MIN_LEN 548 48 | 49 | struct dhcp_packet { 50 | u_int8_t op; /* 0: Message opcode/type */ 51 | u_int8_t htype; /* 1: Hardware addr type (net/if_types.h) */ 52 | u_int8_t hlen; /* 2: Hardware addr length */ 53 | u_int8_t hops; /* 3: Number of relay agent hops from client */ 54 | u_int32_t xid; /* 4: Transaction ID */ 55 | u_int16_t secs; /* 8: Seconds since client started looking */ 56 | u_int16_t flags; /* 10: Flag bits */ 57 | struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ 58 | struct in_addr yiaddr; /* 16: Client IP address */ 59 | struct in_addr siaddr; /* 18: IP address of next server to talk to */ 60 | struct in_addr giaddr; /* 20: DHCP relay agent IP address */ 61 | unsigned char chaddr [16]; /* 24: Client hardware address */ 62 | char sname [DHCP_SNAME_LEN]; /* 40: Server name */ 63 | char file [DHCP_FILE_LEN]; /* 104: Boot filename */ 64 | unsigned char options [DHCP_OPTION_LEN]; 65 | /* 212: Optional parameters 66 | (actual length dependent on MTU). */ 67 | }; 68 | 69 | /* BOOTP (rfc951) message types */ 70 | #define BOOTREQUEST 1 71 | #define BOOTREPLY 2 72 | 73 | /* Possible values for flags field... */ 74 | #define BOOTP_BROADCAST 32768L 75 | 76 | /* Possible values for hardware type (htype) field... */ 77 | #define HTYPE_ETHER 1 /* Ethernet 10Mbps */ 78 | #define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */ 79 | #define HTYPE_FDDI 8 /* FDDI... */ 80 | 81 | /* Magic cookie validating dhcp options field (and bootp vendor 82 | extensions field). */ 83 | #define DHCP_OPTIONS_COOKIE "\143\202\123\143" 84 | 85 | /* DHCP Option codes: */ 86 | 87 | #define DHO_PAD 0 88 | #define DHO_SUBNET_MASK 1 89 | #define DHO_TIME_OFFSET 2 90 | #define DHO_ROUTERS 3 91 | #define DHO_TIME_SERVERS 4 92 | #define DHO_NAME_SERVERS 5 93 | #define DHO_DOMAIN_NAME_SERVERS 6 94 | #define DHO_LOG_SERVERS 7 95 | #define DHO_COOKIE_SERVERS 8 96 | #define DHO_LPR_SERVERS 9 97 | #define DHO_IMPRESS_SERVERS 10 98 | #define DHO_RESOURCE_LOCATION_SERVERS 11 99 | #define DHO_HOST_NAME 12 100 | #define DHO_BOOT_SIZE 13 101 | #define DHO_MERIT_DUMP 14 102 | #define DHO_DOMAIN_NAME 15 103 | #define DHO_SWAP_SERVER 16 104 | #define DHO_ROOT_PATH 17 105 | #define DHO_EXTENSIONS_PATH 18 106 | #define DHO_IP_FORWARDING 19 107 | #define DHO_NON_LOCAL_SOURCE_ROUTING 20 108 | #define DHO_POLICY_FILTER 21 109 | #define DHO_MAX_DGRAM_REASSEMBLY 22 110 | #define DHO_DEFAULT_IP_TTL 23 111 | #define DHO_PATH_MTU_AGING_TIMEOUT 24 112 | #define DHO_PATH_MTU_PLATEAU_TABLE 25 113 | #define DHO_INTERFACE_MTU 26 114 | #define DHO_ALL_SUBNETS_LOCAL 27 115 | #define DHO_BROADCAST_ADDRESS 28 116 | #define DHO_PERFORM_MASK_DISCOVERY 29 117 | #define DHO_MASK_SUPPLIER 30 118 | #define DHO_ROUTER_DISCOVERY 31 119 | #define DHO_ROUTER_SOLICITATION_ADDRESS 32 120 | #define DHO_STATIC_ROUTES 33 121 | #define DHO_TRAILER_ENCAPSULATION 34 122 | #define DHO_ARP_CACHE_TIMEOUT 35 123 | #define DHO_IEEE802_3_ENCAPSULATION 36 124 | #define DHO_DEFAULT_TCP_TTL 37 125 | #define DHO_TCP_KEEPALIVE_INTERVAL 38 126 | #define DHO_TCP_KEEPALIVE_GARBAGE 39 127 | #define DHO_NIS_DOMAIN 40 128 | #define DHO_NIS_SERVERS 41 129 | #define DHO_NTP_SERVERS 42 130 | #define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 131 | #define DHO_NETBIOS_NAME_SERVERS 44 132 | #define DHO_NETBIOS_DD_SERVER 45 133 | #define DHO_NETBIOS_NODE_TYPE 46 134 | #define DHO_NETBIOS_SCOPE 47 135 | #define DHO_FONT_SERVERS 48 136 | #define DHO_X_DISPLAY_MANAGER 49 137 | #define DHO_DHCP_REQUESTED_ADDRESS 50 138 | #define DHO_DHCP_LEASE_TIME 51 139 | #define DHO_DHCP_OPTION_OVERLOAD 52 140 | #define DHO_DHCP_MESSAGE_TYPE 53 141 | #define DHO_DHCP_SERVER_IDENTIFIER 54 142 | #define DHO_DHCP_PARAMETER_REQUEST_LIST 55 143 | #define DHO_DHCP_MESSAGE 56 144 | #define DHO_DHCP_MAX_MESSAGE_SIZE 57 145 | #define DHO_DHCP_RENEWAL_TIME 58 146 | #define DHO_DHCP_REBINDING_TIME 59 147 | #define DHO_VENDOR_CLASS_IDENTIFIER 60 148 | #define DHO_DHCP_CLIENT_IDENTIFIER 61 149 | #define DHO_NWIP_DOMAIN_NAME 62 150 | #define DHO_NWIP_SUBOPTIONS 63 151 | #define DHO_USER_CLASS 77 152 | #define DHO_FQDN 81 153 | #define DHO_DHCP_AGENT_OPTIONS 82 154 | #define DHO_CLIENT_LAST_TRANSACTION_TIME 91 155 | #define DHO_ASSOCIATED_IP 92 156 | #define DHO_SUBNET_SELECTION 118 /* RFC3011! */ 157 | #define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ 158 | #define DHO_VIVCO_SUBOPTIONS 124 159 | #define DHO_VIVSO_SUBOPTIONS 125 160 | /* The DHO_AUTHENTICATE option is not a standard yet, so I've 161 | allocated an option out of the "local" option space for it on a 162 | temporary basis. Once an option code number is assigned, I will 163 | immediately and shamelessly break this, so don't count on it 164 | continuing to work. */ 165 | #define DHO_AUTHENTICATE 210 166 | 167 | #define DHO_END 255 168 | 169 | /* DHCP message types. */ 170 | #define DHCPDISCOVER 1 171 | #define DHCPOFFER 2 172 | #define DHCPREQUEST 3 173 | #define DHCPDECLINE 4 174 | #define DHCPACK 5 175 | #define DHCPNAK 6 176 | #define DHCPRELEASE 7 177 | #define DHCPINFORM 8 178 | #define DHCPLEASEQUERY 10 179 | #define DHCPLEASEUNASSIGNED 11 180 | #define DHCPLEASEUNKNOWN 12 181 | #define DHCPLEASEACTIVE 13 182 | 183 | 184 | /* Relay Agent Information option subtypes: */ 185 | #define RAI_CIRCUIT_ID 1 186 | #define RAI_REMOTE_ID 2 187 | #define RAI_AGENT_ID 3 188 | #define RAI_LINK_SELECT 5 189 | 190 | /* FQDN suboptions: */ 191 | #define FQDN_NO_CLIENT_UPDATE 1 192 | #define FQDN_SERVER_UPDATE 2 193 | #define FQDN_ENCODED 3 194 | #define FQDN_RCODE1 4 195 | #define FQDN_RCODE2 5 196 | #define FQDN_HOSTNAME 6 197 | #define FQDN_DOMAINNAME 7 198 | #define FQDN_FQDN 8 199 | #define FQDN_SUBOPTION_COUNT 8 200 | 201 | /* Enterprise Suboptions: */ 202 | #define VENDOR_ISC_SUBOPTIONS 2495 203 | 204 | #endif /* DHCP_H */ 205 | 206 | -------------------------------------------------------------------------------- /pxe-pdhcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pxe-pdhcp 3 | * 4 | * Copyright (c) 2007-2016 Sadayuki Furuhashi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include "pdhcp.h" 43 | #include "dhcp.h" 44 | 45 | 46 | #ifndef NDEBUG 47 | #define DBG(msg, args...) { char _ts[20] = {0}; time_t _t; struct tm _tm; \ 48 | time(&_t); localtime_r(&_t, &_tm); \ 49 | strftime(_ts, 19, "%b %d %H:%M:%S", &_tm); \ 50 | printf("%s: DEBUG: " __FILE__ ": ", _ts); \ 51 | printf(msg, ## args); printf("\n"); } 52 | #else 53 | #define DBG(msg, args...) { } 54 | #endif 55 | 56 | #define LOG(msg, args...) { char _ts[20] = {0}; time_t _t; struct tm _tm; \ 57 | time(&_t); localtime_r(&_t, &_tm); \ 58 | strftime(_ts, 19, "%b %d %H:%M:%S", &_tm); \ 59 | printf("%s: " __FILE__ ": ", _ts); \ 60 | printf(msg, ## args); printf("\n"); } 61 | 62 | int stopflag = 0; 63 | int foreground = 0; 64 | 65 | struct sockaddr_in server_address; 66 | struct sockaddr_in bcast_address; 67 | struct in_addr tftp_ip; 68 | char* nbp_name; 69 | 70 | int server_socket; 71 | 72 | 73 | void init_packet(struct dhcp_packet *newp, struct dhcp_packet *oldp, u_char mtype) 74 | { 75 | u_char *op; 76 | 77 | memset(newp, 0, sizeof(*newp)); 78 | newp->op = BOOTREPLY; 79 | newp->htype = oldp->htype; 80 | newp->hlen = oldp->hlen; 81 | newp->xid = oldp->xid; 82 | newp->flags = oldp->flags; 83 | 84 | /* set DHCP Cookie */ 85 | memcpy(newp->options, DHCP_OPTIONS_COOKIE, DHCP_OPTIONS_COOKIE_LEN); 86 | op = &newp->options[DHCP_OPTIONS_COOKIE_LEN]; 87 | 88 | /* set DHCP Message Type */ 89 | op[0] = DHO_DHCP_MESSAGE_TYPE; 90 | op[1] = 1; 91 | op[2] = mtype; 92 | op += 3; 93 | 94 | /* set Server Identifier */ 95 | op[0] = DHO_DHCP_SERVER_IDENTIFIER; 96 | op[1] = sizeof(struct in_addr); 97 | memcpy(&op[2], &server_address.sin_addr, sizeof(struct in_addr)); 98 | op += (2 + sizeof(struct in_addr)); 99 | 100 | *op = DHO_END; 101 | } 102 | 103 | void dhcp_reply(struct dhcp_packet *p, struct sockaddr* client_address, socklen_t client_addrlen) 104 | { 105 | int packet_len; 106 | u_char *opt; 107 | u_char optlen; 108 | struct dhcp_packet re; 109 | int res; 110 | 111 | DBG("dhcp_reply start"); 112 | 113 | if (check_dhcp_packet(p) == -1) { 114 | DBG("got a invalid dhcp packet"); 115 | return; 116 | } 117 | if (get_dhcp_message_type(p) == DHCPDISCOVER) { 118 | DBG("got a DHCPDISCOVER on dhcp"); 119 | } else { 120 | DBG("got a non-DHCPDISCOVER dhcp packet"); 121 | return; 122 | } 123 | 124 | /* check vendor class identifier ("PXEClient") */ 125 | res = get_dhcp_option(p, DHO_VENDOR_CLASS_IDENTIFIER, &opt, &optlen); 126 | if (res == -1 || strncmp((char*)opt, PXE_IDENTIFIER_STRING, strlen(PXE_IDENTIFIER_STRING)) != 0) { 127 | LOG("got a non-PXE dhcp packet"); 128 | return; 129 | } 130 | 131 | /* create response */ 132 | init_packet(&re, p, DHCPOFFER); 133 | /* re.ciaddr is 0.0.0.0 */ 134 | /* re.yiaddr is 0.0.0.0 */ 135 | re.siaddr = tftp_ip; 136 | memcpy(re.chaddr, p->chaddr, sizeof(re.chaddr)); 137 | strcpy(re.file, nbp_name); 138 | 139 | /* set vendor class identifier */ 140 | res = add_dhcp_option(&re, DHO_VENDOR_CLASS_IDENTIFIER, 141 | (u_char*)PXE_IDENTIFIER_STRING, 142 | strlen(PXE_IDENTIFIER_STRING)); 143 | if (res == -1) { 144 | DBG("add_dhcp_option() failed"); 145 | return; 146 | } 147 | 148 | /* set vendor options */ 149 | { 150 | u_char vop[3]; 151 | vop[0] = PXE_DISCOVERY_CONTROL; 152 | vop[1] = 1; 153 | vop[2] = PXE_DISCOVERY_CONTROL_BIT3; 154 | if (add_dhcp_option(&re, DHO_VENDOR_ENCAPSULATED_OPTIONS, vop, 3) == -1) { 155 | DBG("add_dhcp_option() failed"); 156 | return; 157 | } 158 | } 159 | 160 | /* send the response */ 161 | packet_len = get_dhcp_packet_len(&re); 162 | res = sendto(server_socket, &re, packet_len, 0, 163 | (struct sockaddr*)&bcast_address, sizeof(bcast_address)); 164 | if (res != packet_len) { 165 | LOG("sendto() failed or was not complete: %s", strerror(errno)); 166 | return; 167 | } 168 | 169 | DBG("dhcp_reply end"); 170 | } 171 | 172 | void pdhcp(void) 173 | { 174 | struct dhcp_packet dhcp_p; 175 | struct sockaddr_in client_address; 176 | socklen_t client_addrlen; 177 | int res; 178 | while(!stopflag) { 179 | memset(&dhcp_p, 0, sizeof(dhcp_p)); 180 | client_addrlen = sizeof(client_address); 181 | res = recvfrom(server_socket, &dhcp_p, sizeof(dhcp_p), 0, 182 | (struct sockaddr*)&client_address, &client_addrlen); 183 | if (res == -1) { 184 | LOG("recvfrom() failed: %s", strerror(errno)); 185 | continue; 186 | } 187 | dhcp_reply(&dhcp_p, (struct sockaddr*)&client_address, 188 | client_addrlen); 189 | } 190 | } 191 | 192 | int init_socket(void) 193 | { 194 | int res; 195 | int on; 196 | 197 | server_socket = socket(PF_INET, SOCK_DGRAM, 0); 198 | if (server_socket == -1) return -1; 199 | 200 | on = 1; 201 | res = setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); 202 | if (res == -1) return -1; 203 | 204 | res = bind(server_socket, (struct sockaddr*)&server_address, 205 | sizeof(server_address)); 206 | if (res == -1) return -1; 207 | 208 | return 0; 209 | } 210 | 211 | void release_all(void) 212 | { 213 | close(server_socket); 214 | } 215 | 216 | void signal_handler(int sig) 217 | { 218 | if (sig == SIGTERM) stopflag = 1; 219 | if (sig == SIGQUIT) stopflag = 1; 220 | if (sig == SIGINT) stopflag = 1; 221 | DBG("got signal %d", sig); 222 | } 223 | int install_signal_handler(void) 224 | { 225 | struct sigaction action; 226 | 227 | /* set SIGTERM handler */ 228 | action.sa_handler = signal_handler; 229 | sigemptyset(&action.sa_mask); 230 | action.sa_flags = 0; 231 | if (sigaction(SIGTERM, &action, NULL) == -1) 232 | return -1; 233 | 234 | /* set SIGQUIT handler */ 235 | action.sa_handler = signal_handler; 236 | sigemptyset(&action.sa_mask); 237 | action.sa_flags = 0; 238 | if (sigaction(SIGQUIT, &action, NULL) == -1) 239 | return -1; 240 | 241 | /* set SIGINT handler */ 242 | action.sa_handler = signal_handler; 243 | sigemptyset(&action.sa_mask); 244 | action.sa_flags = 0; 245 | if (sigaction(SIGINT, &action, NULL) == -1) 246 | return -1; 247 | 248 | return 0; 249 | } 250 | 251 | void usage(const char* prog) 252 | { 253 | fprintf(stderr, "usage: %s [-d] [-i interface] [-l listen address] [-t tftp address] [-b broadcast address] \n", prog); 254 | fprintf(stderr, "-i or (-l, -t and -b), and options are needed.\n"); 255 | } 256 | 257 | void parse_argv(int argc, char* argv[]) 258 | { 259 | int opt; 260 | 261 | char* listen_dev; 262 | int set_server_address = 0; 263 | int set_bcast_address = 0; 264 | int set_tftp_ip = 0; 265 | 266 | memset(&server_address, 0, sizeof(server_address)); 267 | memset(&bcast_address, 0, sizeof(bcast_address)); 268 | memset(&tftp_ip, 0, sizeof(tftp_ip)); 269 | listen_dev = NULL; 270 | nbp_name = NULL; 271 | 272 | 273 | while ((opt = getopt(argc, argv, "i:l:b:t:d")) != -1) { 274 | switch(opt) { 275 | case 'i': 276 | listen_dev = optarg; 277 | break; 278 | case 'l': 279 | if (!inet_aton(optarg, &server_address.sin_addr)) { 280 | perror(optarg); 281 | exit(1); 282 | } 283 | set_server_address = 1; 284 | break; 285 | case 'b': 286 | if (!inet_aton(optarg, &bcast_address.sin_addr)) { 287 | perror(optarg); 288 | exit(1); 289 | } 290 | set_bcast_address = 1; 291 | break; 292 | case 't': 293 | if (!inet_aton(optarg, &tftp_ip)) { 294 | perror(optarg); 295 | exit(1); 296 | } 297 | set_tftp_ip = 1; 298 | break; 299 | case 'd': 300 | foreground = 1; 301 | break; 302 | default: 303 | usage(argv[0]); 304 | exit(1); 305 | } 306 | } 307 | if (optind >= argc) { 308 | usage(argv[0]); 309 | exit(1); 310 | } 311 | nbp_name = argv[optind]; 312 | 313 | if (!set_server_address || !set_tftp_ip || !set_bcast_address) { 314 | /* get these addresses from listen_dev */ 315 | struct ifreq ifr; 316 | int s; 317 | 318 | if (!listen_dev) { 319 | usage(argv[0]); 320 | exit(1); 321 | } 322 | 323 | s = socket(AF_INET, SOCK_DGRAM, 0); 324 | if (s == -1) { 325 | perror("socket() failed"); 326 | exit(1); 327 | } 328 | ifr.ifr_addr.sa_family = AF_INET; 329 | strncpy(ifr.ifr_name, listen_dev, IFNAMSIZ-1); 330 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; 331 | 332 | if (!set_server_address || !set_tftp_ip) { 333 | if (ioctl(s, SIOCGIFADDR, &ifr) == -1) { 334 | perror("cannot get ip address of listen interface"); 335 | close(s); 336 | exit(1); 337 | } 338 | if (!set_server_address) 339 | server_address.sin_addr = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr; 340 | if (!set_tftp_ip) 341 | tftp_ip = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr; 342 | } 343 | 344 | if (!set_bcast_address) { 345 | if (ioctl(s, SIOCGIFBRDADDR, &ifr) == -1) { 346 | perror("cannot get broadcast address of listen interface"); 347 | close(s); 348 | exit(1); 349 | } 350 | bcast_address.sin_addr = 351 | ((struct sockaddr_in*)&ifr.ifr_broadaddr)->sin_addr; 352 | } 353 | 354 | close(s); 355 | } 356 | 357 | server_address.sin_port = ntohs(DHCP_SERVER_PORT); 358 | server_address.sin_family = AF_INET; 359 | bcast_address.sin_port = ntohs(DHCP_CLIENT_PORT); 360 | bcast_address.sin_family = AF_INET; 361 | } 362 | 363 | int main(int argc, char* argv[]) 364 | { 365 | parse_argv(argc, argv); 366 | 367 | printf("listen address: %s:%d\n", inet_ntoa(server_address.sin_addr), 368 | ntohs(server_address.sin_port)); 369 | printf("broadcast address %s:%d\n", inet_ntoa(bcast_address.sin_addr), 370 | ntohs(bcast_address.sin_port)); 371 | printf("tftp address: %s\n", inet_ntoa(tftp_ip)); 372 | printf("nbp name: %s\n", nbp_name); 373 | 374 | /* install signal handler */ 375 | if (install_signal_handler() == -1) { 376 | perror("sigaction() failed"); 377 | exit(-1); 378 | } 379 | 380 | /* init sockets */ 381 | if (init_socket() == -1) { 382 | perror("init_socket()"); 383 | release_all(); 384 | exit(1); 385 | } 386 | 387 | if (foreground) { 388 | pdhcp(); 389 | } else { 390 | daemon(0,0); 391 | pdhcp(); 392 | } 393 | 394 | return 0; 395 | } 396 | 397 | --------------------------------------------------------------------------------