10f66f451Sopenharmony_ci/* dhcpd.c - DHCP server for dynamic network configuration. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2013 Madhur Verma <mad.flexi@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gamil.com> 50f66f451Sopenharmony_ci * Copyright 2015 Yeongdeok Suh <skyducks111@gmail.com> 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * No Standard 80f66f451Sopenharmony_ciUSE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY)) 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciconfig DHCPD 110f66f451Sopenharmony_ci bool "dhcpd" 120f66f451Sopenharmony_ci default n 130f66f451Sopenharmony_ci help 140f66f451Sopenharmony_ci usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE] 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ci -f Run in foreground 170f66f451Sopenharmony_ci -i Interface to use 180f66f451Sopenharmony_ci -S Log to syslog too 190f66f451Sopenharmony_ci -P N Use port N (default ipv4 67, ipv6 547) 200f66f451Sopenharmony_ci -4, -6 Run as a DHCPv4 or DHCPv6 server 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ciconfig DEBUG_DHCP 230f66f451Sopenharmony_ci bool "debugging messeges ON/OFF" 240f66f451Sopenharmony_ci default n 250f66f451Sopenharmony_ci depends on DHCPD 260f66f451Sopenharmony_ci*/ 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ci/* 290f66f451Sopenharmony_ci * TODO 300f66f451Sopenharmony_ci * - Working as an relay agent 310f66f451Sopenharmony_ci * - Rapid commit option support 320f66f451Sopenharmony_ci * - Additional packet options (commented on the middle of sources) 330f66f451Sopenharmony_ci * - Create common modules 340f66f451Sopenharmony_ci */ 350f66f451Sopenharmony_ci 360f66f451Sopenharmony_ci#define FOR_dhcpd 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci#include "toys.h" 390f66f451Sopenharmony_ci#include <linux/sockios.h> 400f66f451Sopenharmony_ci#include <linux/if_ether.h> 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci// Todo: headers not in posix 430f66f451Sopenharmony_ci#include <netinet/ip.h> 440f66f451Sopenharmony_ci#include <netinet/ip6.h> 450f66f451Sopenharmony_ci#include <netinet/udp.h> 460f66f451Sopenharmony_ci#include <netpacket/packet.h> 470f66f451Sopenharmony_ci 480f66f451Sopenharmony_ci#if CFG_DEBUG_DHCP==1 490f66f451Sopenharmony_ci# define dbg(fmt, arg...) printf(fmt, ##arg) 500f66f451Sopenharmony_ci#else 510f66f451Sopenharmony_ci# define dbg(fmt, arg...) 520f66f451Sopenharmony_ci#endif 530f66f451Sopenharmony_ci 540f66f451Sopenharmony_ci#define LOG_SILENT 0x0 550f66f451Sopenharmony_ci#define LOG_CONSOLE 0x1 560f66f451Sopenharmony_ci#define LOG_SYSTEM 0x2 570f66f451Sopenharmony_ci 580f66f451Sopenharmony_ci#define DHCP_MAGIC 0x63825363 590f66f451Sopenharmony_ci 600f66f451Sopenharmony_ci#define DHCPDISCOVER 1 610f66f451Sopenharmony_ci#define DHCPOFFER 2 620f66f451Sopenharmony_ci#define DHCPREQUEST 3 630f66f451Sopenharmony_ci#define DHCPDECLINE 4 640f66f451Sopenharmony_ci#define DHCPACK 5 650f66f451Sopenharmony_ci#define DHCPNAK 6 660f66f451Sopenharmony_ci#define DHCPRELEASE 7 670f66f451Sopenharmony_ci#define DHCPINFORM 8 680f66f451Sopenharmony_ci 690f66f451Sopenharmony_ci#define DHCP6SOLICIT 1 700f66f451Sopenharmony_ci#define DHCP6ADVERTISE 2 // server -> client 710f66f451Sopenharmony_ci#define DHCP6REQUEST 3 720f66f451Sopenharmony_ci#define DHCP6CONFIRM 4 730f66f451Sopenharmony_ci#define DHCP6RENEW 5 740f66f451Sopenharmony_ci#define DHCP6REBIND 6 750f66f451Sopenharmony_ci#define DHCP6REPLY 7 // server -> client 760f66f451Sopenharmony_ci#define DHCP6RELEASE 8 770f66f451Sopenharmony_ci#define DHCP6DECLINE 9 780f66f451Sopenharmony_ci#define DHCP6RECONFIGURE 10 // server -> client 790f66f451Sopenharmony_ci#define DHCP6INFOREQUEST 11 800f66f451Sopenharmony_ci#define DHCP6RELAYFLOW 12 // relay -> relay/server 810f66f451Sopenharmony_ci#define DHCP6RELAYREPLY 13 // server/relay -> relay 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_ci#define DHCP_NUM8 (1<<8) 840f66f451Sopenharmony_ci#define DHCP_NUM16 (1<<9) 850f66f451Sopenharmony_ci#define DHCP_NUM32 DHCP_NUM16 | DHCP_NUM8 860f66f451Sopenharmony_ci#define DHCP_STRING (1<<10) 870f66f451Sopenharmony_ci#define DHCP_STRLST (1<<11) 880f66f451Sopenharmony_ci#define DHCP_IP (1<<12) 890f66f451Sopenharmony_ci#define DHCP_IPLIST (1<<13) 900f66f451Sopenharmony_ci#define DHCP_IPPLST (1<<14) 910f66f451Sopenharmony_ci#define DHCP_STCRTS (1<<15) 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci// DHCP option codes (partial list). See RFC 2132 and 940f66f451Sopenharmony_ci#define DHCP_OPT_PADDING 0x00 950f66f451Sopenharmony_ci#define DHCP_OPT_HOST_NAME DHCP_STRING | 0x0c // either client informs server or server gives name to client 960f66f451Sopenharmony_ci#define DHCP_OPT_REQUESTED_IP DHCP_IP | 0x32 // sent by client if specific IP is wanted 970f66f451Sopenharmony_ci#define DHCP_OPT_LEASE_TIME DHCP_NUM32 | 0x33 980f66f451Sopenharmony_ci#define DHCP_OPT_OPTION_OVERLOAD 0x34 990f66f451Sopenharmony_ci#define DHCP_OPT_MESSAGE_TYPE DHCP_NUM8 | 0x35 1000f66f451Sopenharmony_ci#define DHCP_OPT_SERVER_ID DHCP_IP | 0x36 // by default server's IP 1010f66f451Sopenharmony_ci#define DHCP_OPT_PARAM_REQ DHCP_STRING | 0x37 // list of options client wants 1020f66f451Sopenharmony_ci#define DHCP_OPT_END 0xff 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci// DHCPv6 option codes (partial). See RFC 3315 1050f66f451Sopenharmony_ci#define DHCP6_OPT_CLIENTID 1 1060f66f451Sopenharmony_ci#define DHCP6_OPT_SERVERID 2 1070f66f451Sopenharmony_ci#define DHCP6_OPT_IA_NA 3 1080f66f451Sopenharmony_ci#define DHCP6_OPT_IA_ADDR 5 1090f66f451Sopenharmony_ci#define DHCP6_OPT_ORO 6 1100f66f451Sopenharmony_ci#define DHCP6_OPT_PREFERENCE 7 1110f66f451Sopenharmony_ci#define DHCP6_OPT_ELAPSED_TIME 8 1120f66f451Sopenharmony_ci#define DHCP6_OPT_RELAY_MSG 9 1130f66f451Sopenharmony_ci#define DHCP6_OPT_STATUS_CODE 13 1140f66f451Sopenharmony_ci#define DHCP6_OPT_IA_PD 25 1150f66f451Sopenharmony_ci#define DHCP6_OPT_IA_PREFIX 26 1160f66f451Sopenharmony_ci 1170f66f451Sopenharmony_ci#define DHCP6_STATUS_SUCCESS 0 1180f66f451Sopenharmony_ci#define DHCP6_STATUS_NOADDRSAVAIL 2 1190f66f451Sopenharmony_ci 1200f66f451Sopenharmony_ci#define DHCP6_DUID_LLT 1 1210f66f451Sopenharmony_ci#define DHCP6_DUID_EN 2 1220f66f451Sopenharmony_ci#define DHCP6_DUID_LL 3 1230f66f451Sopenharmony_ci#define DHCP6_DUID_UUID 4 1240f66f451Sopenharmony_ci 1250f66f451Sopenharmony_ciGLOBALS( 1260f66f451Sopenharmony_ci char *iface; 1270f66f451Sopenharmony_ci long port; 1280f66f451Sopenharmony_ci) 1290f66f451Sopenharmony_ci 1300f66f451Sopenharmony_cistruct config_keyword { 1310f66f451Sopenharmony_ci char *keyword; 1320f66f451Sopenharmony_ci int (*handler)(const char *str, void *var); 1330f66f451Sopenharmony_ci void *var; 1340f66f451Sopenharmony_ci char *def; 1350f66f451Sopenharmony_ci}; 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp_msg_s { 1380f66f451Sopenharmony_ci uint8_t op; 1390f66f451Sopenharmony_ci uint8_t htype; 1400f66f451Sopenharmony_ci uint8_t hlen; 1410f66f451Sopenharmony_ci uint8_t hops; 1420f66f451Sopenharmony_ci uint32_t xid; 1430f66f451Sopenharmony_ci uint16_t secs; 1440f66f451Sopenharmony_ci uint16_t flags; 1450f66f451Sopenharmony_ci uint32_t ciaddr; 1460f66f451Sopenharmony_ci uint32_t yiaddr; 1470f66f451Sopenharmony_ci uint32_t nsiaddr; 1480f66f451Sopenharmony_ci uint32_t ngiaddr; 1490f66f451Sopenharmony_ci uint8_t chaddr[16]; 1500f66f451Sopenharmony_ci uint8_t sname[64]; 1510f66f451Sopenharmony_ci uint8_t file[128]; 1520f66f451Sopenharmony_ci uint32_t cookie; 1530f66f451Sopenharmony_ci uint8_t options[308]; 1540f66f451Sopenharmony_ci} dhcp_msg_t; 1550f66f451Sopenharmony_ci 1560f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp6_msg_s { 1570f66f451Sopenharmony_ci uint8_t msgtype; 1580f66f451Sopenharmony_ci uint8_t transaction_id[3]; 1590f66f451Sopenharmony_ci uint8_t options[524]; 1600f66f451Sopenharmony_ci} dhcp6_msg_t; 1610f66f451Sopenharmony_ci 1620f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp_raw_s { 1630f66f451Sopenharmony_ci struct iphdr iph; 1640f66f451Sopenharmony_ci struct udphdr udph; 1650f66f451Sopenharmony_ci dhcp_msg_t dhcp; 1660f66f451Sopenharmony_ci} dhcp_raw_t; 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp6_raw_s { 1690f66f451Sopenharmony_ci struct ip6_hdr iph; 1700f66f451Sopenharmony_ci struct udphdr udph; 1710f66f451Sopenharmony_ci dhcp6_msg_t dhcp6; 1720f66f451Sopenharmony_ci} dhcp6_raw_t; 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_citypedef struct static_lease_s { 1750f66f451Sopenharmony_ci struct static_lease_s *next; 1760f66f451Sopenharmony_ci uint32_t nip; 1770f66f451Sopenharmony_ci int mac[6]; 1780f66f451Sopenharmony_ci} static_lease; 1790f66f451Sopenharmony_ci 1800f66f451Sopenharmony_citypedef struct static_lease6_s { 1810f66f451Sopenharmony_ci struct static_lease6_s *next; 1820f66f451Sopenharmony_ci uint16_t duid_len; 1830f66f451Sopenharmony_ci uint16_t ia_type; 1840f66f451Sopenharmony_ci uint32_t iaid; 1850f66f451Sopenharmony_ci uint8_t nip6[16]; 1860f66f451Sopenharmony_ci uint8_t duid[20]; 1870f66f451Sopenharmony_ci} static_lease6; 1880f66f451Sopenharmony_ci 1890f66f451Sopenharmony_citypedef struct { 1900f66f451Sopenharmony_ci uint32_t expires; 1910f66f451Sopenharmony_ci uint32_t lease_nip; 1920f66f451Sopenharmony_ci uint8_t lease_mac[6]; 1930f66f451Sopenharmony_ci char hostname[20]; 1940f66f451Sopenharmony_ci uint8_t pad[2]; 1950f66f451Sopenharmony_ci} dyn_lease; 1960f66f451Sopenharmony_ci 1970f66f451Sopenharmony_citypedef struct { 1980f66f451Sopenharmony_ci uint16_t duid_len; 1990f66f451Sopenharmony_ci uint16_t ia_type; 2000f66f451Sopenharmony_ci uint32_t expires; 2010f66f451Sopenharmony_ci uint32_t iaid; 2020f66f451Sopenharmony_ci uint8_t lease_nip6[16]; 2030f66f451Sopenharmony_ci uint8_t duid[20]; 2040f66f451Sopenharmony_ci} dyn_lease6; 2050f66f451Sopenharmony_ci 2060f66f451Sopenharmony_citypedef struct option_val_s { 2070f66f451Sopenharmony_ci char *key; 2080f66f451Sopenharmony_ci uint16_t code; 2090f66f451Sopenharmony_ci void *val; 2100f66f451Sopenharmony_ci size_t len; 2110f66f451Sopenharmony_ci} option_val_t; 2120f66f451Sopenharmony_ci 2130f66f451Sopenharmony_cistruct __attribute__((packed)) optval_duid_llt { 2140f66f451Sopenharmony_ci uint16_t type; 2150f66f451Sopenharmony_ci uint16_t hwtype; 2160f66f451Sopenharmony_ci uint32_t time; 2170f66f451Sopenharmony_ci uint8_t lladdr[]; //flexible 2180f66f451Sopenharmony_ci}; 2190f66f451Sopenharmony_ci 2200f66f451Sopenharmony_cistruct __attribute__((packed)) optval_ia_na { 2210f66f451Sopenharmony_ci uint32_t iaid; 2220f66f451Sopenharmony_ci uint32_t t1, t2; 2230f66f451Sopenharmony_ci uint8_t optval[]; //flexible 2240f66f451Sopenharmony_ci}; 2250f66f451Sopenharmony_cistruct __attribute__((packed)) optval_ia_addr { 2260f66f451Sopenharmony_ci uint8_t ipv6_addr[16]; 2270f66f451Sopenharmony_ci uint32_t pref_lifetime; 2280f66f451Sopenharmony_ci uint32_t valid_lifetime; 2290f66f451Sopenharmony_ci}; 2300f66f451Sopenharmony_cistruct __attribute__((packed)) optval_status_code { 2310f66f451Sopenharmony_ci uint16_t status_code; 2320f66f451Sopenharmony_ci uint8_t status_msg[]; //flexible 2330f66f451Sopenharmony_ci}; 2340f66f451Sopenharmony_ci 2350f66f451Sopenharmony_citypedef struct __attribute__((__may_alias__)) server_config_s { 2360f66f451Sopenharmony_ci char *interface; // interface to use 2370f66f451Sopenharmony_ci int ifindex; 2380f66f451Sopenharmony_ci uint8_t server_nip6[16]; 2390f66f451Sopenharmony_ci uint32_t server_nip; 2400f66f451Sopenharmony_ci uint32_t port; 2410f66f451Sopenharmony_ci uint8_t server_mac[6]; // our MAC address (used only for ARP probing) 2420f66f451Sopenharmony_ci void *options[256]; // list of DHCP options loaded from the config file 2430f66f451Sopenharmony_ci /* start,end are in host order: we need to compare start <= ip <= end*/ 2440f66f451Sopenharmony_ci uint32_t start_ip; // start address of leases, in host order 2450f66f451Sopenharmony_ci uint32_t end_ip; // end of leases, in host order 2460f66f451Sopenharmony_ci uint8_t start_ip6[16]; // start address of leases, in IPv6 mode 2470f66f451Sopenharmony_ci uint8_t end_ip6[16]; // end of leases, in IPv6 mode 2480f66f451Sopenharmony_ci uint32_t max_lease_sec; // maximum lease time (host order) 2490f66f451Sopenharmony_ci uint32_t min_lease_sec; // minimum lease time a client can request 2500f66f451Sopenharmony_ci uint32_t max_leases; // maximum number of leases (including reserved addresses) 2510f66f451Sopenharmony_ci uint32_t auto_time; // how long should dhcpd wait before writing a config file. 2520f66f451Sopenharmony_ci // if this is zero, it will only write one on SIGUSR1 2530f66f451Sopenharmony_ci uint32_t decline_time; // how long an address is reserved if a client returns a 2540f66f451Sopenharmony_ci // decline message 2550f66f451Sopenharmony_ci uint32_t conflict_time; // how long an arp conflict offender is leased for 2560f66f451Sopenharmony_ci uint32_t offer_time; // how long an offered address is reserved 2570f66f451Sopenharmony_ci uint32_t siaddr_nip; // "next server" bootp option 2580f66f451Sopenharmony_ci char *lease_file; 2590f66f451Sopenharmony_ci char *lease6_file; 2600f66f451Sopenharmony_ci char *pidfile; 2610f66f451Sopenharmony_ci char *notify_file; // what to run whenever leases are written 2620f66f451Sopenharmony_ci char *sname; // bootp server name 2630f66f451Sopenharmony_ci char *boot_file; // bootp boot file option 2640f66f451Sopenharmony_ci uint32_t pref_lifetime; 2650f66f451Sopenharmony_ci uint32_t valid_lifetime; 2660f66f451Sopenharmony_ci uint32_t t1,t2; 2670f66f451Sopenharmony_ci struct static_lease *static_leases; // List of ip/mac pairs to assign static leases 2680f66f451Sopenharmony_ci} server_config_t; 2690f66f451Sopenharmony_ci 2700f66f451Sopenharmony_citypedef struct __attribute__((__may_alias__)) server_state_s { 2710f66f451Sopenharmony_ci uint8_t client_nip6[16]; 2720f66f451Sopenharmony_ci uint32_t client_port; 2730f66f451Sopenharmony_ci uint8_t rqcode; 2740f66f451Sopenharmony_ci int listensock; 2750f66f451Sopenharmony_ci union { 2760f66f451Sopenharmony_ci dhcp_msg_t rcvd_pkt; 2770f66f451Sopenharmony_ci dhcp6_msg_t rcvd_pkt6; 2780f66f451Sopenharmony_ci } rcvd; 2790f66f451Sopenharmony_ci uint8_t* rqopt; 2800f66f451Sopenharmony_ci union { 2810f66f451Sopenharmony_ci dhcp_msg_t send_pkt; 2820f66f451Sopenharmony_ci dhcp6_msg_t send_pkt6; 2830f66f451Sopenharmony_ci } send; 2840f66f451Sopenharmony_ci union { 2850f66f451Sopenharmony_ci static_lease *sleases; 2860f66f451Sopenharmony_ci static_lease6 *sleases6; 2870f66f451Sopenharmony_ci } leases; 2880f66f451Sopenharmony_ci struct arg_list *dleases; 2890f66f451Sopenharmony_ci} server_state_t; 2900f66f451Sopenharmony_ci 2910f66f451Sopenharmony_cistatic option_val_t options_list[] = { 2920f66f451Sopenharmony_ci {"lease" , DHCP_NUM32 | 0x33, NULL, 0}, 2930f66f451Sopenharmony_ci {"subnet" , DHCP_IP | 0x01, NULL, 0}, 2940f66f451Sopenharmony_ci {"broadcast" , DHCP_IP | 0x1c, NULL, 0}, 2950f66f451Sopenharmony_ci {"router" , DHCP_IP | 0x03, NULL, 0}, 2960f66f451Sopenharmony_ci {"ipttl" , DHCP_NUM8 | 0x17, NULL, 0}, 2970f66f451Sopenharmony_ci {"mtu" , DHCP_NUM16 | 0x1a, NULL, 0}, 2980f66f451Sopenharmony_ci {"hostname" , DHCP_STRING | 0x0c, NULL, 0}, 2990f66f451Sopenharmony_ci {"domain" , DHCP_STRING | 0x0f, NULL, 0}, 3000f66f451Sopenharmony_ci {"search" , DHCP_STRLST | 0x77, NULL, 0}, 3010f66f451Sopenharmony_ci {"nisdomain" , DHCP_STRING | 0x28, NULL, 0}, 3020f66f451Sopenharmony_ci {"timezone" , DHCP_NUM32 | 0x02, NULL, 0}, 3030f66f451Sopenharmony_ci {"tftp" , DHCP_STRING | 0x42, NULL, 0}, 3040f66f451Sopenharmony_ci {"bootfile" , DHCP_STRING | 0x43, NULL, 0}, 3050f66f451Sopenharmony_ci {"bootsize" , DHCP_NUM16 | 0x0d, NULL, 0}, 3060f66f451Sopenharmony_ci {"rootpath" , DHCP_STRING | 0x11, NULL, 0}, 3070f66f451Sopenharmony_ci {"wpad" , DHCP_STRING | 0xfc, NULL, 0}, 3080f66f451Sopenharmony_ci {"serverid" , DHCP_IP | 0x36, NULL, 0}, 3090f66f451Sopenharmony_ci {"message" , DHCP_STRING | 0x38, NULL, 0}, 3100f66f451Sopenharmony_ci {"vlanid" , DHCP_NUM32 | 0x84, NULL, 0}, 3110f66f451Sopenharmony_ci {"vlanpriority" , DHCP_NUM32 | 0x85, NULL, 0}, 3120f66f451Sopenharmony_ci {"dns" , DHCP_IPLIST | 0x06, NULL, 0}, 3130f66f451Sopenharmony_ci {"wins" , DHCP_IPLIST | 0x2c, NULL, 0}, 3140f66f451Sopenharmony_ci {"nissrv" , DHCP_IPLIST | 0x29, NULL, 0}, 3150f66f451Sopenharmony_ci {"ntpsrv" , DHCP_IPLIST | 0x2a, NULL, 0}, 3160f66f451Sopenharmony_ci {"lprsrv" , DHCP_IPLIST | 0x09, NULL, 0}, 3170f66f451Sopenharmony_ci {"swapsrv" , DHCP_IP | 0x10, NULL, 0}, 3180f66f451Sopenharmony_ci {"routes" , DHCP_STCRTS | 0x21, NULL, 0}, 3190f66f451Sopenharmony_ci {"staticroutes" , DHCP_STCRTS | 0x79, NULL, 0}, 3200f66f451Sopenharmony_ci {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0}, 3210f66f451Sopenharmony_ci}; 3220f66f451Sopenharmony_ci 3230f66f451Sopenharmony_cistruct fd_pair { int rd; int wr; }; 3240f66f451Sopenharmony_cistatic server_config_t gconfig; 3250f66f451Sopenharmony_cistatic server_state_t gstate; 3260f66f451Sopenharmony_cistatic uint8_t infomode; 3270f66f451Sopenharmony_cistatic struct fd_pair sigfd; 3280f66f451Sopenharmony_cistatic int constone = 1; 3290f66f451Sopenharmony_cistatic sa_family_t addr_version = AF_INET; 3300f66f451Sopenharmony_ci 3310f66f451Sopenharmony_ci// calculate options size. 3320f66f451Sopenharmony_cistatic int dhcp_opt_size(uint8_t *optionptr) 3330f66f451Sopenharmony_ci{ 3340f66f451Sopenharmony_ci int i = 0; 3350f66f451Sopenharmony_ci for(;optionptr[i] != 0xff; i++) 3360f66f451Sopenharmony_ci if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1; 3370f66f451Sopenharmony_ci return i; 3380f66f451Sopenharmony_ci} 3390f66f451Sopenharmony_ci 3400f66f451Sopenharmony_ci// calculates checksum for dhcp messeges. 3410f66f451Sopenharmony_cistatic uint16_t dhcp_checksum(void *addr, int count) 3420f66f451Sopenharmony_ci{ 3430f66f451Sopenharmony_ci int32_t sum = 0; 3440f66f451Sopenharmony_ci uint16_t tmp = 0, *source = (uint16_t *)addr; 3450f66f451Sopenharmony_ci 3460f66f451Sopenharmony_ci while (count > 1) { 3470f66f451Sopenharmony_ci sum += *source++; 3480f66f451Sopenharmony_ci count -= 2; 3490f66f451Sopenharmony_ci } 3500f66f451Sopenharmony_ci if (count > 0) { 3510f66f451Sopenharmony_ci *(uint8_t*)&tmp = *(uint8_t*)source; 3520f66f451Sopenharmony_ci sum += tmp; 3530f66f451Sopenharmony_ci } 3540f66f451Sopenharmony_ci while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); 3550f66f451Sopenharmony_ci return ~sum; 3560f66f451Sopenharmony_ci} 3570f66f451Sopenharmony_ci 3580f66f451Sopenharmony_ci// gets information of INTERFACE and updates IFINDEX, MAC and IP 3590f66f451Sopenharmony_cistatic int get_interface(const char *interface, int *ifindex, void *oip, 3600f66f451Sopenharmony_ci uint8_t *mac) 3610f66f451Sopenharmony_ci{ 3620f66f451Sopenharmony_ci struct ifreq req; 3630f66f451Sopenharmony_ci struct sockaddr_in *ip; 3640f66f451Sopenharmony_ci struct sockaddr_in6 ip6; 3650f66f451Sopenharmony_ci int fd = xsocket(addr_version, SOCK_RAW, IPPROTO_RAW); 3660f66f451Sopenharmony_ci char ipv6_addr[40] = {0,}; 3670f66f451Sopenharmony_ci 3680f66f451Sopenharmony_ci req.ifr_addr.sa_family = addr_version; 3690f66f451Sopenharmony_ci xstrncpy(req.ifr_name, (char *)interface, IFNAMSIZ); 3700f66f451Sopenharmony_ci 3710f66f451Sopenharmony_ci xioctl(fd, SIOCGIFFLAGS, &req); 3720f66f451Sopenharmony_ci 3730f66f451Sopenharmony_ci if (!(req.ifr_flags & IFF_UP)) return -1; 3740f66f451Sopenharmony_ci 3750f66f451Sopenharmony_ci if (addr_version == AF_INET6) { 3760f66f451Sopenharmony_ci 3770f66f451Sopenharmony_ci FILE *fd6 = fopen("/proc/net/if_inet6", "r"); 3780f66f451Sopenharmony_ci uint8_t *oip6 = (uint8_t*)oip; 3790f66f451Sopenharmony_ci int i; 3800f66f451Sopenharmony_ci 3810f66f451Sopenharmony_ci while(fgets(toybuf, sizeof(toybuf), fd6)) { 3820f66f451Sopenharmony_ci if (!strstr(toybuf, interface)) 3830f66f451Sopenharmony_ci continue; 3840f66f451Sopenharmony_ci 3850f66f451Sopenharmony_ci if (sscanf(toybuf, "%32s \n", ipv6_addr) == 1) 3860f66f451Sopenharmony_ci break; 3870f66f451Sopenharmony_ci } 3880f66f451Sopenharmony_ci fclose(fd6); 3890f66f451Sopenharmony_ci 3900f66f451Sopenharmony_ci if (oip6) { 3910f66f451Sopenharmony_ci char *ptr = ipv6_addr+sizeof(ipv6_addr)-1; 3920f66f451Sopenharmony_ci 3930f66f451Sopenharmony_ci // convert giant hex string into colon-spearated ipv6 address by 3940f66f451Sopenharmony_ci // inserting ':' every 4 characters. 3950f66f451Sopenharmony_ci for (i = 32; i; i--) 3960f66f451Sopenharmony_ci if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':'; 3970f66f451Sopenharmony_ci 3980f66f451Sopenharmony_ci dbg("ipv6 %s\n", ipv6_addr); 3990f66f451Sopenharmony_ci if(inet_pton(AF_INET6, ipv6_addr, &ip6.sin6_addr) <= 0) 4000f66f451Sopenharmony_ci error_msg("inet : the ipv6 address is not proper"); 4010f66f451Sopenharmony_ci else 4020f66f451Sopenharmony_ci memcpy(oip6, ip6.sin6_addr.s6_addr32, sizeof(uint32_t)*4); 4030f66f451Sopenharmony_ci } 4040f66f451Sopenharmony_ci } else { 4050f66f451Sopenharmony_ci uint32_t *oip4 = (uint32_t*)oip; 4060f66f451Sopenharmony_ci if (oip4) { 4070f66f451Sopenharmony_ci xioctl(fd, SIOCGIFADDR, &req); 4080f66f451Sopenharmony_ci ip = (struct sockaddr_in*) &req.ifr_addr; 4090f66f451Sopenharmony_ci dbg("IP %s\n", inet_ntoa(ip->sin_addr)); 4100f66f451Sopenharmony_ci *oip4 = ntohl(ip->sin_addr.s_addr); 4110f66f451Sopenharmony_ci } 4120f66f451Sopenharmony_ci } 4130f66f451Sopenharmony_ci 4140f66f451Sopenharmony_ci if (ifindex) { 4150f66f451Sopenharmony_ci xioctl(fd, SIOCGIFINDEX, &req); 4160f66f451Sopenharmony_ci dbg("Adapter index %d\n", req.ifr_ifindex); 4170f66f451Sopenharmony_ci *ifindex = req.ifr_ifindex; 4180f66f451Sopenharmony_ci } 4190f66f451Sopenharmony_ci if (mac) { 4200f66f451Sopenharmony_ci xioctl(fd, SIOCGIFHWADDR, &req); 4210f66f451Sopenharmony_ci memcpy(mac, req.ifr_hwaddr.sa_data, 6); 4220f66f451Sopenharmony_ci dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 4230f66f451Sopenharmony_ci } 4240f66f451Sopenharmony_ci 4250f66f451Sopenharmony_ci close(fd); 4260f66f451Sopenharmony_ci return 0; 4270f66f451Sopenharmony_ci} 4280f66f451Sopenharmony_ci 4290f66f451Sopenharmony_ci/* 4300f66f451Sopenharmony_ci *logs messeges to syslog or console 4310f66f451Sopenharmony_ci *opening the log is still left with applet. 4320f66f451Sopenharmony_ci *FIXME: move to more relevent lib. probably libc.c 4330f66f451Sopenharmony_ci */ 4340f66f451Sopenharmony_cistatic void infomsg(uint8_t infomode, char *s, ...) 4350f66f451Sopenharmony_ci{ 4360f66f451Sopenharmony_ci int used; 4370f66f451Sopenharmony_ci char *msg; 4380f66f451Sopenharmony_ci va_list p, t; 4390f66f451Sopenharmony_ci 4400f66f451Sopenharmony_ci if (infomode == LOG_SILENT) return; 4410f66f451Sopenharmony_ci va_start(p, s); 4420f66f451Sopenharmony_ci va_copy(t, p); 4430f66f451Sopenharmony_ci used = vsnprintf(NULL, 0, s, t); 4440f66f451Sopenharmony_ci used++; 4450f66f451Sopenharmony_ci va_end(t); 4460f66f451Sopenharmony_ci 4470f66f451Sopenharmony_ci msg = xmalloc(used); 4480f66f451Sopenharmony_ci vsnprintf(msg, used, s, p); 4490f66f451Sopenharmony_ci va_end(p); 4500f66f451Sopenharmony_ci 4510f66f451Sopenharmony_ci if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg); 4520f66f451Sopenharmony_ci if (infomode & LOG_CONSOLE) printf("%s\n", msg); 4530f66f451Sopenharmony_ci free(msg); 4540f66f451Sopenharmony_ci} 4550f66f451Sopenharmony_ci 4560f66f451Sopenharmony_ci/* 4570f66f451Sopenharmony_ci * Writes self PID in file PATH 4580f66f451Sopenharmony_ci * FIXME: libc implementation only writes in /var/run 4590f66f451Sopenharmony_ci * this is more generic as some implemenation may provide 4600f66f451Sopenharmony_ci * arguments to write in specific file. as dhcpd does. 4610f66f451Sopenharmony_ci */ 4620f66f451Sopenharmony_cistatic void write_pid(char *path) 4630f66f451Sopenharmony_ci{ 4640f66f451Sopenharmony_ci int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666); 4650f66f451Sopenharmony_ci if (pidfile > 0) { 4660f66f451Sopenharmony_ci char pidbuf[12]; 4670f66f451Sopenharmony_ci 4680f66f451Sopenharmony_ci sprintf(pidbuf, "%u", (unsigned)getpid()); 4690f66f451Sopenharmony_ci write(pidfile, pidbuf, strlen(pidbuf)); 4700f66f451Sopenharmony_ci close(pidfile); 4710f66f451Sopenharmony_ci } 4720f66f451Sopenharmony_ci} 4730f66f451Sopenharmony_ci 4740f66f451Sopenharmony_ci// Generic signal handler real handling is done in main funcrion. 4750f66f451Sopenharmony_cistatic void signal_handler(int sig) 4760f66f451Sopenharmony_ci{ 4770f66f451Sopenharmony_ci unsigned char ch = sig; 4780f66f451Sopenharmony_ci if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n"); 4790f66f451Sopenharmony_ci} 4800f66f451Sopenharmony_ci 4810f66f451Sopenharmony_ci// signal setup for SIGUSR1 SIGTERM 4820f66f451Sopenharmony_cistatic int setup_signal() 4830f66f451Sopenharmony_ci{ 4840f66f451Sopenharmony_ci if (pipe((int *)&sigfd) < 0) { 4850f66f451Sopenharmony_ci dbg("signal pipe failed\n"); 4860f66f451Sopenharmony_ci return -1; 4870f66f451Sopenharmony_ci } 4880f66f451Sopenharmony_ci fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC); 4890f66f451Sopenharmony_ci fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC); 4900f66f451Sopenharmony_ci int flags = fcntl(sigfd.wr, F_GETFL); 4910f66f451Sopenharmony_ci fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK); 4920f66f451Sopenharmony_ci signal(SIGUSR1, signal_handler); 4930f66f451Sopenharmony_ci signal(SIGTERM, signal_handler); 4940f66f451Sopenharmony_ci return 0; 4950f66f451Sopenharmony_ci} 4960f66f451Sopenharmony_ci 4970f66f451Sopenharmony_ci// String STR to UINT32 conversion strored in VAR 4980f66f451Sopenharmony_cistatic int strtou32(const char *str, void *var) 4990f66f451Sopenharmony_ci{ 5000f66f451Sopenharmony_ci char *endptr = NULL; 5010f66f451Sopenharmony_ci int base = 10; 5020f66f451Sopenharmony_ci errno=0; 5030f66f451Sopenharmony_ci *((uint32_t*)(var)) = 0; 5040f66f451Sopenharmony_ci if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) { 5050f66f451Sopenharmony_ci base = 16; 5060f66f451Sopenharmony_ci str+=2; 5070f66f451Sopenharmony_ci } 5080f66f451Sopenharmony_ci 5090f66f451Sopenharmony_ci long ret_val = strtol(str, &endptr, base); 5100f66f451Sopenharmony_ci if (errno) infomsg(infomode, "config : Invalid num %s",str); 5110f66f451Sopenharmony_ci else if (endptr && (*endptr!='\0'||endptr == str)) 5120f66f451Sopenharmony_ci infomsg(infomode, "config : Not a valid num %s",str); 5130f66f451Sopenharmony_ci else *((uint32_t*)(var)) = (uint32_t)ret_val; 5140f66f451Sopenharmony_ci return 0; 5150f66f451Sopenharmony_ci} 5160f66f451Sopenharmony_ci 5170f66f451Sopenharmony_ci// copy string STR in variable VAR 5180f66f451Sopenharmony_cistatic int strinvar(const char *str, void *var) 5190f66f451Sopenharmony_ci{ 5200f66f451Sopenharmony_ci char **dest = var; 5210f66f451Sopenharmony_ci if (*dest) free(*dest); 5220f66f451Sopenharmony_ci *dest = strdup(str); 5230f66f451Sopenharmony_ci return 0; 5240f66f451Sopenharmony_ci} 5250f66f451Sopenharmony_ci 5260f66f451Sopenharmony_ci// IP String STR to binary data. 5270f66f451Sopenharmony_cistatic int striptovar(const char *str, void *var) 5280f66f451Sopenharmony_ci{ 5290f66f451Sopenharmony_ci *((uint32_t*)(var)) = 0; 5300f66f451Sopenharmony_ci if(!str) { 5310f66f451Sopenharmony_ci error_msg("config : NULL address string \n"); 5320f66f451Sopenharmony_ci return -1; 5330f66f451Sopenharmony_ci } 5340f66f451Sopenharmony_ci if((inet_pton(AF_INET6, str, var)<=0) && (inet_pton(AF_INET, str, var)<=0)) { 5350f66f451Sopenharmony_ci error_msg("config : wrong address %s \n", str); 5360f66f451Sopenharmony_ci return -1; 5370f66f451Sopenharmony_ci } 5380f66f451Sopenharmony_ci return 0; 5390f66f451Sopenharmony_ci} 5400f66f451Sopenharmony_ci 5410f66f451Sopenharmony_ci// String to dhcp option conversion 5420f66f451Sopenharmony_cistatic int strtoopt(const char *str, void *var) 5430f66f451Sopenharmony_ci{ 5440f66f451Sopenharmony_ci char *option, *valstr, *grp, *tp; 5450f66f451Sopenharmony_ci uint32_t optcode = 0, inf = infomode, convtmp, mask, nip, router; 5460f66f451Sopenharmony_ci uint16_t flag = 0; 5470f66f451Sopenharmony_ci int count, size = ARRAY_LEN(options_list); 5480f66f451Sopenharmony_ci 5490f66f451Sopenharmony_ci if (!*str) return 0; 5500f66f451Sopenharmony_ci if (!(option = strtok((char*)str, " \t="))) return -1; 5510f66f451Sopenharmony_ci 5520f66f451Sopenharmony_ci infomode = LOG_SILENT; 5530f66f451Sopenharmony_ci strtou32(option, (uint32_t*)&optcode); 5540f66f451Sopenharmony_ci infomode = inf; 5550f66f451Sopenharmony_ci 5560f66f451Sopenharmony_ci if (optcode > 0 && optcode < 256) { // raw option 5570f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 5580f66f451Sopenharmony_ci if ((options_list[count].code & 0X00FF) == optcode) { 5590f66f451Sopenharmony_ci flag = (options_list[count].code & 0XFF00); 5600f66f451Sopenharmony_ci break; 5610f66f451Sopenharmony_ci } 5620f66f451Sopenharmony_ci } 5630f66f451Sopenharmony_ci } else { //string option 5640f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 5650f66f451Sopenharmony_ci if (!strncmp(options_list[count].key, option, strlen(options_list[count].key))) { 5660f66f451Sopenharmony_ci flag = (options_list[count].code & 0XFF00); 5670f66f451Sopenharmony_ci optcode = (options_list[count].code & 0X00FF); 5680f66f451Sopenharmony_ci break; 5690f66f451Sopenharmony_ci } 5700f66f451Sopenharmony_ci } 5710f66f451Sopenharmony_ci } 5720f66f451Sopenharmony_ci if (count == size) { 5730f66f451Sopenharmony_ci infomsg(inf, "config : Obsolete OR Unknown Option : %s", option); 5740f66f451Sopenharmony_ci return -1; 5750f66f451Sopenharmony_ci } 5760f66f451Sopenharmony_ci 5770f66f451Sopenharmony_ci if (!flag || !optcode) return -1; 5780f66f451Sopenharmony_ci 5790f66f451Sopenharmony_ci if (!(valstr = strtok(NULL, " \t"))) { 5800f66f451Sopenharmony_ci dbg("config : option %s has no value defined.\n", option); 5810f66f451Sopenharmony_ci return -1; 5820f66f451Sopenharmony_ci } 5830f66f451Sopenharmony_ci dbg(" value : %-20s : ", valstr); 5840f66f451Sopenharmony_ci switch (flag) { 5850f66f451Sopenharmony_ci case DHCP_NUM32: 5860f66f451Sopenharmony_ci options_list[count].len = sizeof(uint32_t); 5870f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint32_t)); 5880f66f451Sopenharmony_ci strtou32(valstr, &convtmp); 5890f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint32_t)); 5900f66f451Sopenharmony_ci break; 5910f66f451Sopenharmony_ci case DHCP_NUM16: 5920f66f451Sopenharmony_ci options_list[count].len = sizeof(uint16_t); 5930f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint16_t)); 5940f66f451Sopenharmony_ci strtou32(valstr, &convtmp); 5950f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint16_t)); 5960f66f451Sopenharmony_ci break; 5970f66f451Sopenharmony_ci case DHCP_NUM8: 5980f66f451Sopenharmony_ci options_list[count].len = sizeof(uint8_t); 5990f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint8_t)); 6000f66f451Sopenharmony_ci strtou32(valstr, &convtmp); 6010f66f451Sopenharmony_ci memcpy(options_list[count].val, &convtmp, sizeof(uint8_t)); 6020f66f451Sopenharmony_ci break; 6030f66f451Sopenharmony_ci case DHCP_IP: 6040f66f451Sopenharmony_ci options_list[count].len = sizeof(uint32_t); 6050f66f451Sopenharmony_ci options_list[count].val = xmalloc(sizeof(uint32_t)); 6060f66f451Sopenharmony_ci striptovar(valstr, options_list[count].val); 6070f66f451Sopenharmony_ci break; 6080f66f451Sopenharmony_ci case DHCP_STRING: 6090f66f451Sopenharmony_ci options_list[count].len = strlen(valstr); 6100f66f451Sopenharmony_ci options_list[count].val = strdup(valstr); 6110f66f451Sopenharmony_ci break; 6120f66f451Sopenharmony_ci case DHCP_IPLIST: 6130f66f451Sopenharmony_ci while(valstr){ 6140f66f451Sopenharmony_ci options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t)); 6150f66f451Sopenharmony_ci striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len); 6160f66f451Sopenharmony_ci options_list[count].len += sizeof(uint32_t); 6170f66f451Sopenharmony_ci valstr = strtok(NULL," \t"); 6180f66f451Sopenharmony_ci } 6190f66f451Sopenharmony_ci break; 6200f66f451Sopenharmony_ci case DHCP_IPPLST: 6210f66f451Sopenharmony_ci break; 6220f66f451Sopenharmony_ci case DHCP_STCRTS: 6230f66f451Sopenharmony_ci /* Option binary format: 6240f66f451Sopenharmony_ci * mask [one byte, 0..32] 6250f66f451Sopenharmony_ci * ip [0..4 bytes depending on mask] 6260f66f451Sopenharmony_ci * router [4 bytes] 6270f66f451Sopenharmony_ci * may be repeated 6280f66f451Sopenharmony_ci * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 6290f66f451Sopenharmony_ci */ 6300f66f451Sopenharmony_ci grp = strtok(valstr, ",");; 6310f66f451Sopenharmony_ci while(grp){ 6320f66f451Sopenharmony_ci while(*grp == ' ' || *grp == '\t') grp++; 6330f66f451Sopenharmony_ci tp = strchr(grp, '/'); 6340f66f451Sopenharmony_ci if (!tp) error_exit("wrong formatted static route option"); 6350f66f451Sopenharmony_ci *tp = '\0'; 6360f66f451Sopenharmony_ci mask = strtol(++tp, &tp, 10); 6370f66f451Sopenharmony_ci if (striptovar(grp, (uint8_t*)&nip)<0) error_exit("wrong formatted static route option"); 6380f66f451Sopenharmony_ci while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++; 6390f66f451Sopenharmony_ci if (striptovar(tp, (uint8_t*)&router)<0) error_exit("wrong formatted static route option"); 6400f66f451Sopenharmony_ci options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4); 6410f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1); 6420f66f451Sopenharmony_ci options_list[count].len += 1; 6430f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8); 6440f66f451Sopenharmony_ci options_list[count].len += mask/8; 6450f66f451Sopenharmony_ci memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4); 6460f66f451Sopenharmony_ci options_list[count].len += 4; 6470f66f451Sopenharmony_ci tp = NULL; 6480f66f451Sopenharmony_ci grp = strtok(NULL, ","); 6490f66f451Sopenharmony_ci } 6500f66f451Sopenharmony_ci break; 6510f66f451Sopenharmony_ci } 6520f66f451Sopenharmony_ci return 0; 6530f66f451Sopenharmony_ci} 6540f66f451Sopenharmony_ci 6550f66f451Sopenharmony_ci// Reads Static leases from STR and updates inner structures. 6560f66f451Sopenharmony_cistatic int get_staticlease(const char *str, void *var) 6570f66f451Sopenharmony_ci{ 6580f66f451Sopenharmony_ci struct static_lease_s *sltmp; 6590f66f451Sopenharmony_ci char *tkmac, *tkip; 6600f66f451Sopenharmony_ci int count; 6610f66f451Sopenharmony_ci 6620f66f451Sopenharmony_ci if (!*str) return 0; 6630f66f451Sopenharmony_ci 6640f66f451Sopenharmony_ci if (!(tkmac = strtok((char*)str, " \t"))) { 6650f66f451Sopenharmony_ci infomsg(infomode, "config : static lease : mac not found"); 6660f66f451Sopenharmony_ci return 0; 6670f66f451Sopenharmony_ci } 6680f66f451Sopenharmony_ci if (!(tkip = strtok(NULL, " \t"))) { 6690f66f451Sopenharmony_ci infomsg(infomode, "config : static lease : no ip bind to mac %s", tkmac); 6700f66f451Sopenharmony_ci return 0; 6710f66f451Sopenharmony_ci } 6720f66f451Sopenharmony_ci sltmp = xzalloc(sizeof(struct static_lease_s)); 6730f66f451Sopenharmony_ci for (count = 0; count < 6; count++, tkmac++) { 6740f66f451Sopenharmony_ci errno = 0; 6750f66f451Sopenharmony_ci sltmp->mac[count] = strtol(tkmac, &tkmac, 16); 6760f66f451Sopenharmony_ci if (sltmp->mac[count]>255 || sltmp->mac[count]<0 || (*tkmac && *tkmac!=':') || errno) { 6770f66f451Sopenharmony_ci infomsg(infomode, "config : static lease : mac address wrong format"); 6780f66f451Sopenharmony_ci free(sltmp); 6790f66f451Sopenharmony_ci return 0; 6800f66f451Sopenharmony_ci } 6810f66f451Sopenharmony_ci } 6820f66f451Sopenharmony_ci striptovar(tkip, &sltmp->nip); 6830f66f451Sopenharmony_ci sltmp->next = gstate.leases.sleases; 6840f66f451Sopenharmony_ci gstate.leases.sleases = sltmp; 6850f66f451Sopenharmony_ci 6860f66f451Sopenharmony_ci return 0; 6870f66f451Sopenharmony_ci} 6880f66f451Sopenharmony_ci 6890f66f451Sopenharmony_cistatic struct config_keyword keywords[] = { 6900f66f451Sopenharmony_ci// keyword handler variable address default 6910f66f451Sopenharmony_ci {"start" , striptovar , (void*)&gconfig.start_ip , "192.168.0.20"}, 6920f66f451Sopenharmony_ci {"end" , striptovar , (void*)&gconfig.end_ip , "192.168.0.254"}, 6930f66f451Sopenharmony_ci {"interface" , strinvar , (void*)&gconfig.interface , "eth0"}, 6940f66f451Sopenharmony_ci {"port" , strtou32 , (void*)&gconfig.port , "67"}, 6950f66f451Sopenharmony_ci {"min_lease" , strtou32 , (void*)&gconfig.min_lease_sec, "60"}, 6960f66f451Sopenharmony_ci {"max_leases" , strtou32 , (void*)&gconfig.max_leases , "235"}, 6970f66f451Sopenharmony_ci {"auto_time" , strtou32 , (void*)&gconfig.auto_time , "7200"}, 6980f66f451Sopenharmony_ci {"decline_time" , strtou32 , (void*)&gconfig.decline_time , "3600"}, 6990f66f451Sopenharmony_ci {"conflict_time", strtou32 , (void*)&gconfig.conflict_time, "3600"}, 7000f66f451Sopenharmony_ci {"offer_time" , strtou32 , (void*)&gconfig.offer_time , "60"}, 7010f66f451Sopenharmony_ci {"lease_file" , strinvar , (void*)&gconfig.lease_file , "/var/lib/misc/dhcpd.leases"}, //LEASES_FILE 7020f66f451Sopenharmony_ci {"lease6_file" , strinvar , (void*)&gconfig.lease6_file , "/var/lib/misc/dhcpd6.leases"}, //LEASES_FILE 7030f66f451Sopenharmony_ci {"pidfile" , strinvar , (void*)&gconfig.pidfile , "/var/run/dhcpd.pid"}, //DPID_FILE 7040f66f451Sopenharmony_ci {"siaddr" , striptovar , (void*)&gconfig.siaddr_nip , "0.0.0.0"}, 7050f66f451Sopenharmony_ci {"option" , strtoopt , (void*)&gconfig.options , ""}, 7060f66f451Sopenharmony_ci {"opt" , strtoopt , (void*)&gconfig.options , ""}, 7070f66f451Sopenharmony_ci {"notify_file" , strinvar , (void*)&gconfig.notify_file , ""}, 7080f66f451Sopenharmony_ci {"sname" , strinvar , (void*)&gconfig.sname , ""}, 7090f66f451Sopenharmony_ci {"boot_file" , strinvar , (void*)&gconfig.boot_file , ""}, 7100f66f451Sopenharmony_ci {"static_lease" , get_staticlease , (void*)&gconfig.static_leases, ""}, 7110f66f451Sopenharmony_ci {"start6" , striptovar , (void*)&gconfig.start_ip6 , "2001:620:40b:555::100"}, 7120f66f451Sopenharmony_ci {"end6" , striptovar , (void*)&gconfig.end_ip6 , "2001:620:40b:555::200"}, 7130f66f451Sopenharmony_ci {"preferred_lifetime" , strtou32 , (void*)&gconfig.pref_lifetime, "3600"}, 7140f66f451Sopenharmony_ci {"valid_lifetime" , strtou32 , (void*)&gconfig.valid_lifetime, "7200"}, 7150f66f451Sopenharmony_ci {"t1" , strtou32 , (void*)&gconfig.t1 , "3600"}, 7160f66f451Sopenharmony_ci {"t2" , strtou32 , (void*)&gconfig.t2 , "5400"}, 7170f66f451Sopenharmony_ci}; 7180f66f451Sopenharmony_ci 7190f66f451Sopenharmony_ci// Parses the server config file and updates the global server config accordingly. 7200f66f451Sopenharmony_cistatic int parse_server_config(char *config_file, struct config_keyword *confkey) 7210f66f451Sopenharmony_ci{ 7220f66f451Sopenharmony_ci FILE *fs = NULL; 7230f66f451Sopenharmony_ci char *confline_temp = NULL,*confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL}; 7240f66f451Sopenharmony_ci int len, linelen, tcount, count, size = ARRAY_LEN(keywords); 7250f66f451Sopenharmony_ci 7260f66f451Sopenharmony_ci for (count = 0; count < size; count++) 7270f66f451Sopenharmony_ci if (confkey[count].handler) 7280f66f451Sopenharmony_ci confkey[count].handler(confkey[count].def, confkey[count].var); 7290f66f451Sopenharmony_ci 7300f66f451Sopenharmony_ci if (!(fs = fopen(config_file, "r"))) perror_msg("%s", config_file); 7310f66f451Sopenharmony_ci for (len = 0, linelen = 0; fs;) { 7320f66f451Sopenharmony_ci len = getline(&confline_temp, (size_t*) &linelen, fs); 7330f66f451Sopenharmony_ci confline = confline_temp; 7340f66f451Sopenharmony_ci if (len <= 0) break; 7350f66f451Sopenharmony_ci for (; *confline == ' '; confline++, len--); 7360f66f451Sopenharmony_ci if ((confline[0] == '#') || (confline[0] == '\n')) goto free_conf_continue; 7370f66f451Sopenharmony_ci tk = strchr(confline, '#'); 7380f66f451Sopenharmony_ci if (tk) { 7390f66f451Sopenharmony_ci for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--); 7400f66f451Sopenharmony_ci *tk = '\0'; 7410f66f451Sopenharmony_ci } 7420f66f451Sopenharmony_ci tk = strchr(confline, '\n'); 7430f66f451Sopenharmony_ci if (tk) { 7440f66f451Sopenharmony_ci for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--); 7450f66f451Sopenharmony_ci *tk = '\0'; 7460f66f451Sopenharmony_ci } 7470f66f451Sopenharmony_ci for (tcount=0, tk=strtok(confline, " \t"); tk && (tcount < 2); 7480f66f451Sopenharmony_ci tcount++, tk=strtok(NULL,(tcount==1)?"":" \t")) { 7490f66f451Sopenharmony_ci while ((*tk == '\t') || (*tk == ' ')) tk++; 7500f66f451Sopenharmony_ci tokens[tcount] = xstrdup(tk); 7510f66f451Sopenharmony_ci } 7520f66f451Sopenharmony_ci if (tcount<=1) goto free_tk0_continue; 7530f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 7540f66f451Sopenharmony_ci if (!strcmp(confkey[count].keyword,tokens[0])) { 7550f66f451Sopenharmony_ci dbg("got config : %15s : ", confkey[count].keyword); 7560f66f451Sopenharmony_ci if (confkey[count].handler(tokens[1], confkey[count].var) == 0) 7570f66f451Sopenharmony_ci dbg("%s \n", tokens[1]); 7580f66f451Sopenharmony_ci break; 7590f66f451Sopenharmony_ci } 7600f66f451Sopenharmony_ci } 7610f66f451Sopenharmony_ci if (tokens[1]) { free(tokens[1]); tokens[1] = NULL; } 7620f66f451Sopenharmony_cifree_tk0_continue: 7630f66f451Sopenharmony_ci if (tokens[0]) { free(tokens[0]); tokens[0] = NULL; } 7640f66f451Sopenharmony_cifree_conf_continue: 7650f66f451Sopenharmony_ci free(confline_temp); 7660f66f451Sopenharmony_ci confline_temp = NULL; 7670f66f451Sopenharmony_ci } 7680f66f451Sopenharmony_ci if (fs) fclose(fs); 7690f66f451Sopenharmony_ci return 0; 7700f66f451Sopenharmony_ci} 7710f66f451Sopenharmony_ci 7720f66f451Sopenharmony_ci// opens UDP socket for listen ipv6 packets 7730f66f451Sopenharmony_cistatic int open_listensock6(void) 7740f66f451Sopenharmony_ci{ 7750f66f451Sopenharmony_ci struct sockaddr_in6 addr6; 7760f66f451Sopenharmony_ci struct ipv6_mreq mreq; 7770f66f451Sopenharmony_ci 7780f66f451Sopenharmony_ci if (gstate.listensock > 0) close(gstate.listensock); 7790f66f451Sopenharmony_ci 7800f66f451Sopenharmony_ci dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface); 7810f66f451Sopenharmony_ci 7820f66f451Sopenharmony_ci gstate.listensock = xsocket(PF_INET6, SOCK_DGRAM, 0); 7830f66f451Sopenharmony_ci setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone)); 7840f66f451Sopenharmony_ci setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_CHECKSUM, &constone, sizeof(constone)); 7850f66f451Sopenharmony_ci 7860f66f451Sopenharmony_ci if (setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &constone, 7870f66f451Sopenharmony_ci sizeof(constone)) == -1) { 7880f66f451Sopenharmony_ci error_msg("failed to receive ipv6 packets.\n"); 7890f66f451Sopenharmony_ci close(gstate.listensock); 7900f66f451Sopenharmony_ci return -1; 7910f66f451Sopenharmony_ci } 7920f66f451Sopenharmony_ci 7930f66f451Sopenharmony_ci setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, gconfig.interface, strlen(gconfig.interface)+1); 7940f66f451Sopenharmony_ci 7950f66f451Sopenharmony_ci memset(&addr6, 0, sizeof(addr6)); 7960f66f451Sopenharmony_ci addr6.sin6_family = AF_INET6; 7970f66f451Sopenharmony_ci addr6.sin6_port = htons(gconfig.port); //SERVER_PORT 7980f66f451Sopenharmony_ci addr6.sin6_scope_id = if_nametoindex(gconfig.interface); 7990f66f451Sopenharmony_ci //Listening for multicast packet 8000f66f451Sopenharmony_ci inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr); 8010f66f451Sopenharmony_ci 8020f66f451Sopenharmony_ci if (bind(gstate.listensock, (struct sockaddr *) &addr6, sizeof(addr6)) == -1) { 8030f66f451Sopenharmony_ci close(gstate.listensock); 8040f66f451Sopenharmony_ci perror_exit("bind failed"); 8050f66f451Sopenharmony_ci } 8060f66f451Sopenharmony_ci 8070f66f451Sopenharmony_ci memset(&mreq, 0, sizeof(mreq)); 8080f66f451Sopenharmony_ci mreq.ipv6mr_interface = if_nametoindex(gconfig.interface); 8090f66f451Sopenharmony_ci memcpy(&mreq.ipv6mr_multiaddr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)); 8100f66f451Sopenharmony_ci 8110f66f451Sopenharmony_ci if(setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) { 8120f66f451Sopenharmony_ci error_msg("failed to join a multicast group.\n"); 8130f66f451Sopenharmony_ci close(gstate.listensock); 8140f66f451Sopenharmony_ci return -1; 8150f66f451Sopenharmony_ci } 8160f66f451Sopenharmony_ci 8170f66f451Sopenharmony_ci dbg("OPEN : success\n"); 8180f66f451Sopenharmony_ci return 0; 8190f66f451Sopenharmony_ci} 8200f66f451Sopenharmony_ci 8210f66f451Sopenharmony_ci// opens UDP socket for listen 8220f66f451Sopenharmony_cistatic int open_listensock(void) 8230f66f451Sopenharmony_ci{ 8240f66f451Sopenharmony_ci struct sockaddr_in addr; 8250f66f451Sopenharmony_ci struct ifreq ifr; 8260f66f451Sopenharmony_ci 8270f66f451Sopenharmony_ci if (gstate.listensock > 0) close(gstate.listensock); 8280f66f451Sopenharmony_ci 8290f66f451Sopenharmony_ci dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface); 8300f66f451Sopenharmony_ci gstate.listensock = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 8310f66f451Sopenharmony_ci setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone)); 8320f66f451Sopenharmony_ci if (setsockopt(gstate.listensock, SOL_SOCKET, SO_BROADCAST, &constone, sizeof(constone)) == -1) { 8330f66f451Sopenharmony_ci error_msg("failed to receive brodcast packets.\n"); 8340f66f451Sopenharmony_ci close(gstate.listensock); 8350f66f451Sopenharmony_ci return -1; 8360f66f451Sopenharmony_ci } 8370f66f451Sopenharmony_ci memset(&ifr, 0, sizeof(ifr)); 8380f66f451Sopenharmony_ci xstrncpy(ifr.ifr_name, gconfig.interface, IFNAMSIZ); 8390f66f451Sopenharmony_ci setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); 8400f66f451Sopenharmony_ci 8410f66f451Sopenharmony_ci memset(&addr, 0, sizeof(addr)); 8420f66f451Sopenharmony_ci addr.sin_family = AF_INET; 8430f66f451Sopenharmony_ci addr.sin_port = htons(gconfig.port); //SERVER_PORT 8440f66f451Sopenharmony_ci addr.sin_addr.s_addr = INADDR_ANY ; 8450f66f451Sopenharmony_ci 8460f66f451Sopenharmony_ci if (bind(gstate.listensock, (struct sockaddr *) &addr, sizeof(addr))) { 8470f66f451Sopenharmony_ci close(gstate.listensock); 8480f66f451Sopenharmony_ci perror_exit("bind failed"); 8490f66f451Sopenharmony_ci } 8500f66f451Sopenharmony_ci dbg("OPEN : success\n"); 8510f66f451Sopenharmony_ci return 0; 8520f66f451Sopenharmony_ci} 8530f66f451Sopenharmony_ci 8540f66f451Sopenharmony_cistatic int send_packet6(uint8_t relay, uint8_t *client_lla, uint16_t optlen) 8550f66f451Sopenharmony_ci{ 8560f66f451Sopenharmony_ci struct sockaddr_ll dest_sll; 8570f66f451Sopenharmony_ci dhcp6_raw_t packet; 8580f66f451Sopenharmony_ci unsigned padding; 8590f66f451Sopenharmony_ci int fd, result = -1; 8600f66f451Sopenharmony_ci 8610f66f451Sopenharmony_ci memset(&packet, 0, sizeof(dhcp6_raw_t)); 8620f66f451Sopenharmony_ci memcpy(&packet.dhcp6, &gstate.send.send_pkt6, sizeof(dhcp6_msg_t)); 8630f66f451Sopenharmony_ci padding = sizeof(packet.dhcp6.options) - optlen; 8640f66f451Sopenharmony_ci 8650f66f451Sopenharmony_ci if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))) < 0) { 8660f66f451Sopenharmony_ci dbg("SEND : ipv6 socket failed\n"); 8670f66f451Sopenharmony_ci return -1; 8680f66f451Sopenharmony_ci } 8690f66f451Sopenharmony_ci memset(&dest_sll, 0, sizeof(dest_sll)); 8700f66f451Sopenharmony_ci dest_sll.sll_family = AF_PACKET; 8710f66f451Sopenharmony_ci dest_sll.sll_protocol = htons(ETH_P_IPV6); 8720f66f451Sopenharmony_ci dest_sll.sll_ifindex = gconfig.ifindex; 8730f66f451Sopenharmony_ci dest_sll.sll_halen = ETH_ALEN; 8740f66f451Sopenharmony_ci memcpy(dest_sll.sll_addr, client_lla, sizeof(uint8_t)*6); 8750f66f451Sopenharmony_ci 8760f66f451Sopenharmony_ci if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) { 8770f66f451Sopenharmony_ci dbg("SEND : bind failed\n"); 8780f66f451Sopenharmony_ci close(fd); 8790f66f451Sopenharmony_ci return -1; 8800f66f451Sopenharmony_ci } 8810f66f451Sopenharmony_ci memcpy(&packet.iph.ip6_src, &gconfig.server_nip6, sizeof(uint32_t)*4); 8820f66f451Sopenharmony_ci memcpy(&packet.iph.ip6_dst, &gstate.client_nip6, sizeof(uint32_t)*4); 8830f66f451Sopenharmony_ci 8840f66f451Sopenharmony_ci packet.udph.source = htons(gconfig.port); //SERVER_PORT 8850f66f451Sopenharmony_ci packet.udph.dest = gstate.client_port; //CLIENT_PORT 8860f66f451Sopenharmony_ci packet.udph.len = htons(sizeof(dhcp6_raw_t) - sizeof(struct ip6_hdr) - padding); 8870f66f451Sopenharmony_ci packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ntohs(packet.udph.len) + 0x11); 8880f66f451Sopenharmony_ci packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp6_raw_t) - padding); 8890f66f451Sopenharmony_ci packet.iph.ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000); 8900f66f451Sopenharmony_ci packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = packet.udph.len; 8910f66f451Sopenharmony_ci packet.iph.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP; 8920f66f451Sopenharmony_ci packet.iph.ip6_ctlun.ip6_un1.ip6_un1_hlim = 0x64; 8930f66f451Sopenharmony_ci 8940f66f451Sopenharmony_ci result = sendto(fd, &packet, sizeof(dhcp6_raw_t)-padding, 8950f66f451Sopenharmony_ci 0, (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 8960f66f451Sopenharmony_ci 8970f66f451Sopenharmony_ci dbg("sendto %d\n", result); 8980f66f451Sopenharmony_ci close(fd); 8990f66f451Sopenharmony_ci if (result < 0) dbg("PACKET send error\n"); 9000f66f451Sopenharmony_ci return result; 9010f66f451Sopenharmony_ci} 9020f66f451Sopenharmony_ci 9030f66f451Sopenharmony_ci// Sends data through raw socket. 9040f66f451Sopenharmony_cistatic int send_packet(uint8_t broadcast) 9050f66f451Sopenharmony_ci{ 9060f66f451Sopenharmony_ci struct sockaddr_ll dest_sll; 9070f66f451Sopenharmony_ci dhcp_raw_t packet; 9080f66f451Sopenharmony_ci unsigned padding; 9090f66f451Sopenharmony_ci int fd, result = -1; 9100f66f451Sopenharmony_ci uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 9110f66f451Sopenharmony_ci 9120f66f451Sopenharmony_ci memset(&packet, 0, sizeof(dhcp_raw_t)); 9130f66f451Sopenharmony_ci memcpy(&packet.dhcp, &gstate.send.send_pkt, sizeof(dhcp_msg_t)); 9140f66f451Sopenharmony_ci 9150f66f451Sopenharmony_ci if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 9160f66f451Sopenharmony_ci dbg("SEND : socket failed\n"); 9170f66f451Sopenharmony_ci return -1; 9180f66f451Sopenharmony_ci } 9190f66f451Sopenharmony_ci memset(&dest_sll, 0, sizeof(dest_sll)); 9200f66f451Sopenharmony_ci dest_sll.sll_family = AF_PACKET; 9210f66f451Sopenharmony_ci dest_sll.sll_protocol = htons(ETH_P_IP); 9220f66f451Sopenharmony_ci dest_sll.sll_ifindex = gconfig.ifindex; 9230f66f451Sopenharmony_ci dest_sll.sll_halen = 6; 9240f66f451Sopenharmony_ci memcpy(dest_sll.sll_addr, (broadcast)?bmacaddr:gstate.rcvd.rcvd_pkt.chaddr , 6); 9250f66f451Sopenharmony_ci 9260f66f451Sopenharmony_ci if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) { 9270f66f451Sopenharmony_ci dbg("SEND : bind failed\n"); 9280f66f451Sopenharmony_ci close(fd); 9290f66f451Sopenharmony_ci return -1; 9300f66f451Sopenharmony_ci } 9310f66f451Sopenharmony_ci padding = 308 - 1 - dhcp_opt_size(gstate.send.send_pkt.options); 9320f66f451Sopenharmony_ci packet.iph.protocol = IPPROTO_UDP; 9330f66f451Sopenharmony_ci packet.iph.saddr = gconfig.server_nip; 9340f66f451Sopenharmony_ci packet.iph.daddr = (broadcast || (gstate.rcvd.rcvd_pkt.ciaddr == 0))? 9350f66f451Sopenharmony_ci INADDR_BROADCAST : gstate.rcvd.rcvd_pkt.ciaddr; 9360f66f451Sopenharmony_ci packet.udph.source = htons(gconfig.port);//SERVER_PORT 9370f66f451Sopenharmony_ci packet.udph.dest = gstate.client_port; //CLIENT_PORT 9380f66f451Sopenharmony_ci packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding); 9390f66f451Sopenharmony_ci packet.iph.tot_len = packet.udph.len; 9400f66f451Sopenharmony_ci packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding); 9410f66f451Sopenharmony_ci packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding); 9420f66f451Sopenharmony_ci packet.iph.ihl = sizeof(packet.iph) >> 2; 9430f66f451Sopenharmony_ci packet.iph.version = IPVERSION; 9440f66f451Sopenharmony_ci packet.iph.ttl = IPDEFTTL; 9450f66f451Sopenharmony_ci packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph)); 9460f66f451Sopenharmony_ci 9470f66f451Sopenharmony_ci result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0, 9480f66f451Sopenharmony_ci (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 9490f66f451Sopenharmony_ci 9500f66f451Sopenharmony_ci dbg("sendto %d\n", result); 9510f66f451Sopenharmony_ci close(fd); 9520f66f451Sopenharmony_ci if (result < 0) dbg("PACKET send error\n"); 9530f66f451Sopenharmony_ci return result; 9540f66f451Sopenharmony_ci} 9550f66f451Sopenharmony_ci 9560f66f451Sopenharmony_cistatic int read_packet6(void) 9570f66f451Sopenharmony_ci{ 9580f66f451Sopenharmony_ci int ret; 9590f66f451Sopenharmony_ci struct sockaddr_in6 c_addr; 9600f66f451Sopenharmony_ci socklen_t c_addr_size = sizeof(c_addr); 9610f66f451Sopenharmony_ci 9620f66f451Sopenharmony_ci memset(&gstate.rcvd.rcvd_pkt6, 0, sizeof(dhcp6_msg_t)); 9630f66f451Sopenharmony_ci ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt6, sizeof(dhcp6_msg_t), 9640f66f451Sopenharmony_ci 0, (struct sockaddr*) &c_addr, &c_addr_size); 9650f66f451Sopenharmony_ci memcpy(gstate.client_nip6, &c_addr.sin6_addr, sizeof(uint32_t)*4); 9660f66f451Sopenharmony_ci memcpy(&gstate.client_port, &c_addr.sin6_port, sizeof(uint32_t)); 9670f66f451Sopenharmony_ci if (ret < 0) { 9680f66f451Sopenharmony_ci dbg("Packet read error, ignoring. \n"); 9690f66f451Sopenharmony_ci return ret; // returns -1 9700f66f451Sopenharmony_ci } 9710f66f451Sopenharmony_ci if (gstate.rcvd.rcvd_pkt6.msgtype < 1) { 9720f66f451Sopenharmony_ci dbg("Bad message type, igroning. \n"); 9730f66f451Sopenharmony_ci return -2; 9740f66f451Sopenharmony_ci } 9750f66f451Sopenharmony_ci 9760f66f451Sopenharmony_ci dbg("Received an ipv6 packet. Size : %d \n", ret); 9770f66f451Sopenharmony_ci return ret; 9780f66f451Sopenharmony_ci} 9790f66f451Sopenharmony_ci 9800f66f451Sopenharmony_ci// Reads from UDP socket 9810f66f451Sopenharmony_cistatic int read_packet(void) 9820f66f451Sopenharmony_ci{ 9830f66f451Sopenharmony_ci int ret; 9840f66f451Sopenharmony_ci struct sockaddr_in c_addr; 9850f66f451Sopenharmony_ci socklen_t c_addr_size = sizeof(c_addr); 9860f66f451Sopenharmony_ci 9870f66f451Sopenharmony_ci memset(&gstate.rcvd.rcvd_pkt, 0, sizeof(dhcp_msg_t)); 9880f66f451Sopenharmony_ci ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t), 9890f66f451Sopenharmony_ci 0, (struct sockaddr*) &c_addr, &c_addr_size); 9900f66f451Sopenharmony_ci memcpy(&gstate.client_port, &c_addr.sin_port, sizeof(uint32_t)); 9910f66f451Sopenharmony_ci /*ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t));*/ 9920f66f451Sopenharmony_ci if (ret < 0) { 9930f66f451Sopenharmony_ci dbg("Packet read error, ignoring. \n"); 9940f66f451Sopenharmony_ci return ret; // returns -1 9950f66f451Sopenharmony_ci } 9960f66f451Sopenharmony_ci if (gstate.rcvd.rcvd_pkt.cookie != htonl(DHCP_MAGIC)) { 9970f66f451Sopenharmony_ci dbg("Packet with bad magic, ignoring. \n"); 9980f66f451Sopenharmony_ci return -2; 9990f66f451Sopenharmony_ci } 10000f66f451Sopenharmony_ci if (gstate.rcvd.rcvd_pkt.op != 1) { //BOOTPREQUEST 10010f66f451Sopenharmony_ci dbg("Not a BOOT REQUEST ignoring. \n"); 10020f66f451Sopenharmony_ci return -2; 10030f66f451Sopenharmony_ci } 10040f66f451Sopenharmony_ci if (gstate.rcvd.rcvd_pkt.hlen != 6) { 10050f66f451Sopenharmony_ci dbg("hlen != 6 ignoring. \n"); 10060f66f451Sopenharmony_ci return -2; 10070f66f451Sopenharmony_ci } 10080f66f451Sopenharmony_ci dbg("Received a packet. Size : %d \n", ret); 10090f66f451Sopenharmony_ci return ret; 10100f66f451Sopenharmony_ci} 10110f66f451Sopenharmony_ci 10120f66f451Sopenharmony_ci// Preapres a dhcp packet with defaults and configs 10130f66f451Sopenharmony_cistatic uint8_t* prepare_send_pkt(void) 10140f66f451Sopenharmony_ci{ 10150f66f451Sopenharmony_ci memset((void*)&gstate.send.send_pkt, 0, sizeof(gstate.send.send_pkt)); 10160f66f451Sopenharmony_ci gstate.send.send_pkt.op = 2; //BOOTPREPLY 10170f66f451Sopenharmony_ci gstate.send.send_pkt.htype = 1; 10180f66f451Sopenharmony_ci gstate.send.send_pkt.hlen = 6; 10190f66f451Sopenharmony_ci gstate.send.send_pkt.xid = gstate.rcvd.rcvd_pkt.xid; 10200f66f451Sopenharmony_ci gstate.send.send_pkt.cookie = htonl(DHCP_MAGIC); 10210f66f451Sopenharmony_ci gstate.send.send_pkt.nsiaddr = gconfig.server_nip; 10220f66f451Sopenharmony_ci memcpy(gstate.send.send_pkt.chaddr, gstate.rcvd.rcvd_pkt.chaddr, 16); 10230f66f451Sopenharmony_ci gstate.send.send_pkt.options[0] = DHCP_OPT_END; 10240f66f451Sopenharmony_ci return gstate.send.send_pkt.options; 10250f66f451Sopenharmony_ci} 10260f66f451Sopenharmony_ci 10270f66f451Sopenharmony_cistatic uint8_t* prepare_send_pkt6(uint16_t opt) 10280f66f451Sopenharmony_ci{ 10290f66f451Sopenharmony_ci memset((void*)&gstate.send.send_pkt6, 0, sizeof(gstate.send.send_pkt6)); 10300f66f451Sopenharmony_ci gstate.send.send_pkt6.msgtype = opt; 10310f66f451Sopenharmony_ci memcpy(gstate.send.send_pkt6.transaction_id, gstate.rcvd.rcvd_pkt6.transaction_id, 3); 10320f66f451Sopenharmony_ci return gstate.send.send_pkt6.options; 10330f66f451Sopenharmony_ci} 10340f66f451Sopenharmony_ci 10350f66f451Sopenharmony_ci// Sets a option value in dhcp packet's option field 10360f66f451Sopenharmony_cistatic uint8_t* set_optval(uint8_t *optptr, uint16_t opt, void *var, size_t len) 10370f66f451Sopenharmony_ci{ 10380f66f451Sopenharmony_ci while (*optptr != DHCP_OPT_END) optptr++; 10390f66f451Sopenharmony_ci *optptr++ = (uint8_t)(opt & 0x00FF); 10400f66f451Sopenharmony_ci *optptr++ = (uint8_t) len; 10410f66f451Sopenharmony_ci memcpy(optptr, var, len); 10420f66f451Sopenharmony_ci optptr += len; 10430f66f451Sopenharmony_ci *optptr = DHCP_OPT_END; 10440f66f451Sopenharmony_ci return optptr; 10450f66f451Sopenharmony_ci} 10460f66f451Sopenharmony_ci 10470f66f451Sopenharmony_cistatic uint8_t* set_optval6(uint8_t *optptr, uint16_t opt, void *var, size_t len) 10480f66f451Sopenharmony_ci{ 10490f66f451Sopenharmony_ci *((uint16_t*)optptr) = htons(opt); 10500f66f451Sopenharmony_ci *(uint16_t*)(optptr+2) = htons(len); 10510f66f451Sopenharmony_ci memcpy(optptr+4, var, len); 10520f66f451Sopenharmony_ci optptr += len+4; 10530f66f451Sopenharmony_ci return optptr; 10540f66f451Sopenharmony_ci} 10550f66f451Sopenharmony_ci 10560f66f451Sopenharmony_ci// Gets a option value from dhcp packet's option field 10570f66f451Sopenharmony_cistatic uint8_t* get_optval(uint8_t *optptr, uint16_t opt, void *var) 10580f66f451Sopenharmony_ci{ 10590f66f451Sopenharmony_ci size_t len; 10600f66f451Sopenharmony_ci uint8_t overloaded = 0; 10610f66f451Sopenharmony_ci 10620f66f451Sopenharmony_ci while (1) { 10630f66f451Sopenharmony_ci while (*optptr == DHCP_OPT_PADDING) optptr++; 10640f66f451Sopenharmony_ci if ((*optptr & 0x00FF) == DHCP_OPT_END) break; 10650f66f451Sopenharmony_ci if ((*optptr & 0x00FF) == DHCP_OPT_OPTION_OVERLOAD) { 10660f66f451Sopenharmony_ci overloaded = optptr[2]; 10670f66f451Sopenharmony_ci optptr += optptr[1] + 2; 10680f66f451Sopenharmony_ci } 10690f66f451Sopenharmony_ci len = optptr[1]; 10700f66f451Sopenharmony_ci if (*optptr == (opt & 0x00FF)) 10710f66f451Sopenharmony_ci switch (opt & 0xFF00) { 10720f66f451Sopenharmony_ci case DHCP_NUM32: // FALLTHROUGH 10730f66f451Sopenharmony_ci case DHCP_IP: 10740f66f451Sopenharmony_ci memcpy(var, optptr+2, sizeof(uint32_t)); 10750f66f451Sopenharmony_ci optptr += len + 2; 10760f66f451Sopenharmony_ci return optptr; 10770f66f451Sopenharmony_ci break; 10780f66f451Sopenharmony_ci case DHCP_NUM16: 10790f66f451Sopenharmony_ci memcpy(var, optptr+2, sizeof(uint16_t)); 10800f66f451Sopenharmony_ci optptr += len + 2; 10810f66f451Sopenharmony_ci return optptr; 10820f66f451Sopenharmony_ci break; 10830f66f451Sopenharmony_ci case DHCP_NUM8: 10840f66f451Sopenharmony_ci memcpy(var, optptr+2, sizeof(uint8_t)); 10850f66f451Sopenharmony_ci optptr += len + 2; 10860f66f451Sopenharmony_ci return optptr; 10870f66f451Sopenharmony_ci break; 10880f66f451Sopenharmony_ci case DHCP_STRING: 10890f66f451Sopenharmony_ci var = xstrndup((char*) optptr, len); 10900f66f451Sopenharmony_ci optptr += len + 2; 10910f66f451Sopenharmony_ci return optptr; 10920f66f451Sopenharmony_ci break; 10930f66f451Sopenharmony_ci } 10940f66f451Sopenharmony_ci optptr += len + 2; 10950f66f451Sopenharmony_ci } 10960f66f451Sopenharmony_ci if ((overloaded == 1) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.file, opt, var); 10970f66f451Sopenharmony_ci if ((overloaded == 2) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.sname, opt, var); 10980f66f451Sopenharmony_ci return optptr; 10990f66f451Sopenharmony_ci} 11000f66f451Sopenharmony_ci 11010f66f451Sopenharmony_cistatic uint8_t* get_optval6(uint8_t *optptr, uint16_t opt, uint16_t *datalen, void **var) 11020f66f451Sopenharmony_ci{ 11030f66f451Sopenharmony_ci uint16_t optcode; 11040f66f451Sopenharmony_ci uint16_t len; 11050f66f451Sopenharmony_ci 11060f66f451Sopenharmony_ci memcpy(&optcode, optptr, sizeof(uint16_t)); 11070f66f451Sopenharmony_ci memcpy(&len, optptr+2, sizeof(uint16_t)); 11080f66f451Sopenharmony_ci if(!optcode) { 11090f66f451Sopenharmony_ci dbg("Option %d is not exist.\n", opt); 11100f66f451Sopenharmony_ci return optptr; 11110f66f451Sopenharmony_ci } 11120f66f451Sopenharmony_ci optcode = ntohs(optcode); 11130f66f451Sopenharmony_ci len = ntohs(len); 11140f66f451Sopenharmony_ci 11150f66f451Sopenharmony_ci if (opt == optcode) { 11160f66f451Sopenharmony_ci *var = xmalloc(len); 11170f66f451Sopenharmony_ci memcpy(*var, optptr+4, len); 11180f66f451Sopenharmony_ci optptr = optptr + len + 4; 11190f66f451Sopenharmony_ci memcpy(datalen, &len, sizeof(uint16_t)); 11200f66f451Sopenharmony_ci } 11210f66f451Sopenharmony_ci else { 11220f66f451Sopenharmony_ci optptr = get_optval6(optptr+len+4, opt, datalen, var); 11230f66f451Sopenharmony_ci } 11240f66f451Sopenharmony_ci 11250f66f451Sopenharmony_ci return optptr; 11260f66f451Sopenharmony_ci} 11270f66f451Sopenharmony_ci 11280f66f451Sopenharmony_ci// Retrives Requested Parameter list from dhcp req packet. 11290f66f451Sopenharmony_cistatic uint8_t get_reqparam(uint8_t **list) 11300f66f451Sopenharmony_ci{ 11310f66f451Sopenharmony_ci uint8_t len, *optptr; 11320f66f451Sopenharmony_ci if(*list) free(*list); 11330f66f451Sopenharmony_ci for (optptr = gstate.rcvd.rcvd_pkt.options; 11340f66f451Sopenharmony_ci *optptr && *optptr!=((DHCP_OPT_PARAM_REQ) & 0x00FF); optptr+=optptr[1]+2); 11350f66f451Sopenharmony_ci len = *++optptr; 11360f66f451Sopenharmony_ci *list = xzalloc(len+1); 11370f66f451Sopenharmony_ci memcpy(*list, ++optptr, len); 11380f66f451Sopenharmony_ci return len; 11390f66f451Sopenharmony_ci} 11400f66f451Sopenharmony_ci 11410f66f451Sopenharmony_ci// Sets values of req param in dhcp offer packet. 11420f66f451Sopenharmony_cistatic uint8_t* set_reqparam(uint8_t *optptr, uint8_t *list) 11430f66f451Sopenharmony_ci{ 11440f66f451Sopenharmony_ci uint8_t reqcode; 11450f66f451Sopenharmony_ci int count, size = ARRAY_LEN(options_list); 11460f66f451Sopenharmony_ci 11470f66f451Sopenharmony_ci while (*list) { 11480f66f451Sopenharmony_ci reqcode = *list++; 11490f66f451Sopenharmony_ci for (count = 0; count < size; count++) { 11500f66f451Sopenharmony_ci if ((options_list[count].code & 0X00FF)==reqcode) { 11510f66f451Sopenharmony_ci if (!(options_list[count].len) || !(options_list[count].val)) break; 11520f66f451Sopenharmony_ci for (; *optptr && *optptr!=DHCP_OPT_END; optptr+=optptr[1]+2); 11530f66f451Sopenharmony_ci *optptr++ = (uint8_t) (options_list[count].code & 0x00FF); 11540f66f451Sopenharmony_ci *optptr++ = (uint8_t) options_list[count].len; 11550f66f451Sopenharmony_ci memcpy(optptr, options_list[count].val, options_list[count].len); 11560f66f451Sopenharmony_ci optptr += options_list[count].len; 11570f66f451Sopenharmony_ci *optptr = DHCP_OPT_END; 11580f66f451Sopenharmony_ci break; 11590f66f451Sopenharmony_ci } 11600f66f451Sopenharmony_ci } 11610f66f451Sopenharmony_ci } 11620f66f451Sopenharmony_ci return optptr; 11630f66f451Sopenharmony_ci} 11640f66f451Sopenharmony_ci 11650f66f451Sopenharmony_cistatic void run_notify(char **argv) 11660f66f451Sopenharmony_ci{ 11670f66f451Sopenharmony_ci struct stat sts; 11680f66f451Sopenharmony_ci volatile int error = 0; 11690f66f451Sopenharmony_ci pid_t pid; 11700f66f451Sopenharmony_ci 11710f66f451Sopenharmony_ci if (stat(argv[0], &sts) == -1 && errno == ENOENT) { 11720f66f451Sopenharmony_ci infomsg(infomode, "notify file: %s : not exist.", argv[0]); 11730f66f451Sopenharmony_ci return; 11740f66f451Sopenharmony_ci } 11750f66f451Sopenharmony_ci fflush(NULL); 11760f66f451Sopenharmony_ci 11770f66f451Sopenharmony_ci pid = vfork(); 11780f66f451Sopenharmony_ci if (pid < 0) { 11790f66f451Sopenharmony_ci dbg("Fork failed.\n"); 11800f66f451Sopenharmony_ci return; 11810f66f451Sopenharmony_ci } 11820f66f451Sopenharmony_ci if (!pid) { 11830f66f451Sopenharmony_ci execvp(argv[0], argv); 11840f66f451Sopenharmony_ci error = errno; 11850f66f451Sopenharmony_ci _exit(111); 11860f66f451Sopenharmony_ci } 11870f66f451Sopenharmony_ci if (error) { 11880f66f451Sopenharmony_ci waitpid(pid, NULL, 0); 11890f66f451Sopenharmony_ci errno = error; 11900f66f451Sopenharmony_ci } 11910f66f451Sopenharmony_ci dbg("script complete.\n"); 11920f66f451Sopenharmony_ci} 11930f66f451Sopenharmony_ci 11940f66f451Sopenharmony_cistatic void write_leasefile(void) 11950f66f451Sopenharmony_ci{ 11960f66f451Sopenharmony_ci int fd; 11970f66f451Sopenharmony_ci uint32_t curr, tmp_time; 11980f66f451Sopenharmony_ci int64_t timestamp; 11990f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases; 12000f66f451Sopenharmony_ci dyn_lease *dls; 12010f66f451Sopenharmony_ci 12020f66f451Sopenharmony_ci if ((fd = open(gconfig.lease_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 12030f66f451Sopenharmony_ci perror_msg("can't open %s ", gconfig.lease_file); 12040f66f451Sopenharmony_ci } else { 12050f66f451Sopenharmony_ci curr = timestamp = time(NULL); 12060f66f451Sopenharmony_ci timestamp = SWAP_BE64(timestamp); 12070f66f451Sopenharmony_ci writeall(fd, ×tamp, sizeof(timestamp)); 12080f66f451Sopenharmony_ci 12090f66f451Sopenharmony_ci while (listdls) { 12100f66f451Sopenharmony_ci dls = (dyn_lease*)listdls->arg; 12110f66f451Sopenharmony_ci tmp_time = dls->expires; 12120f66f451Sopenharmony_ci dls->expires -= curr; 12130f66f451Sopenharmony_ci if ((int32_t) dls->expires < 0) goto skip; 12140f66f451Sopenharmony_ci dls->expires = htonl(dls->expires); 12150f66f451Sopenharmony_ci writeall(fd, dls, sizeof(dyn_lease)); 12160f66f451Sopenharmony_ciskip: 12170f66f451Sopenharmony_ci dls->expires = tmp_time; 12180f66f451Sopenharmony_ci listdls = listdls->next; 12190f66f451Sopenharmony_ci } 12200f66f451Sopenharmony_ci close(fd); 12210f66f451Sopenharmony_ci if (gconfig.notify_file) { 12220f66f451Sopenharmony_ci char *argv[3]; 12230f66f451Sopenharmony_ci argv[0] = gconfig.notify_file; 12240f66f451Sopenharmony_ci argv[1] = gconfig.lease_file; 12250f66f451Sopenharmony_ci argv[2] = NULL; 12260f66f451Sopenharmony_ci run_notify(argv); 12270f66f451Sopenharmony_ci } 12280f66f451Sopenharmony_ci } 12290f66f451Sopenharmony_ci} 12300f66f451Sopenharmony_ci 12310f66f451Sopenharmony_cistatic void write_lease6file(void) 12320f66f451Sopenharmony_ci{ 12330f66f451Sopenharmony_ci int fd; 12340f66f451Sopenharmony_ci uint32_t curr, tmp_time; 12350f66f451Sopenharmony_ci int64_t timestamp; 12360f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases; 12370f66f451Sopenharmony_ci dyn_lease6 *dls6; 12380f66f451Sopenharmony_ci 12390f66f451Sopenharmony_ci if ((fd = open(gconfig.lease6_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 12400f66f451Sopenharmony_ci perror_msg("can't open %s ", gconfig.lease6_file); 12410f66f451Sopenharmony_ci } else { 12420f66f451Sopenharmony_ci curr = timestamp = time(NULL); 12430f66f451Sopenharmony_ci timestamp = SWAP_BE64(timestamp); 12440f66f451Sopenharmony_ci writeall(fd, ×tamp, sizeof(timestamp)); 12450f66f451Sopenharmony_ci 12460f66f451Sopenharmony_ci while (listdls) { 12470f66f451Sopenharmony_ci dls6 = (dyn_lease6*)listdls->arg; 12480f66f451Sopenharmony_ci tmp_time = dls6->expires; 12490f66f451Sopenharmony_ci dls6->expires -= curr; 12500f66f451Sopenharmony_ci if ((int32_t) dls6->expires < 0) goto skip; 12510f66f451Sopenharmony_ci dls6->expires = htonl(dls6->expires); 12520f66f451Sopenharmony_ci writeall(fd, dls6, sizeof(dyn_lease6)); 12530f66f451Sopenharmony_ciskip: 12540f66f451Sopenharmony_ci dls6->expires = tmp_time; 12550f66f451Sopenharmony_ci listdls = listdls->next; 12560f66f451Sopenharmony_ci } 12570f66f451Sopenharmony_ci close(fd); 12580f66f451Sopenharmony_ci if (gconfig.notify_file) { 12590f66f451Sopenharmony_ci char *argv[3]; 12600f66f451Sopenharmony_ci argv[0] = gconfig.notify_file; 12610f66f451Sopenharmony_ci argv[1] = gconfig.lease6_file; 12620f66f451Sopenharmony_ci argv[2] = NULL; 12630f66f451Sopenharmony_ci run_notify(argv); 12640f66f451Sopenharmony_ci } 12650f66f451Sopenharmony_ci } 12660f66f451Sopenharmony_ci} 12670f66f451Sopenharmony_ci 12680f66f451Sopenharmony_ci// Update max lease time from options. 12690f66f451Sopenharmony_cistatic void set_maxlease(void) 12700f66f451Sopenharmony_ci{ 12710f66f451Sopenharmony_ci int count, size = ARRAY_LEN(options_list); 12720f66f451Sopenharmony_ci for (count = 0; count < size; count++) 12730f66f451Sopenharmony_ci if (options_list[count].val && options_list[count].code == (DHCP_OPT_LEASE_TIME)) { 12740f66f451Sopenharmony_ci gconfig.max_lease_sec = *((uint32_t*)options_list[count].val); 12750f66f451Sopenharmony_ci break; 12760f66f451Sopenharmony_ci } 12770f66f451Sopenharmony_ci if (!gconfig.max_lease_sec) gconfig.max_lease_sec = (60*60*24*10);// DEFAULT_LEASE_TIME; 12780f66f451Sopenharmony_ci} 12790f66f451Sopenharmony_ci 12800f66f451Sopenharmony_ci// Returns lease time for client. 12810f66f451Sopenharmony_cistatic uint32_t get_lease(uint32_t req_exp) 12820f66f451Sopenharmony_ci{ 12830f66f451Sopenharmony_ci uint32_t now = time(NULL); 12840f66f451Sopenharmony_ci req_exp = req_exp - now; 12850f66f451Sopenharmony_ci if(addr_version == AF_INET6) { 12860f66f451Sopenharmony_ci if ((req_exp <= 0) || req_exp > gconfig.pref_lifetime || 12870f66f451Sopenharmony_ci req_exp > gconfig.valid_lifetime) { 12880f66f451Sopenharmony_ci if ((gconfig.pref_lifetime > gconfig.valid_lifetime)) { 12890f66f451Sopenharmony_ci error_msg("The valid lifetime must be greater than the preferred lifetime, \ 12900f66f451Sopenharmony_ci setting to valid lifetime %u", gconfig.valid_lifetime); 12910f66f451Sopenharmony_ci return gconfig.valid_lifetime; 12920f66f451Sopenharmony_ci } 12930f66f451Sopenharmony_ci return gconfig.pref_lifetime; 12940f66f451Sopenharmony_ci } 12950f66f451Sopenharmony_ci } else { 12960f66f451Sopenharmony_ci if ((req_exp <= 0) || (req_exp > gconfig.max_lease_sec)) 12970f66f451Sopenharmony_ci return gconfig.max_lease_sec; 12980f66f451Sopenharmony_ci 12990f66f451Sopenharmony_ci if (req_exp < gconfig.min_lease_sec) 13000f66f451Sopenharmony_ci return gconfig.min_lease_sec; 13010f66f451Sopenharmony_ci } 13020f66f451Sopenharmony_ci 13030f66f451Sopenharmony_ci return req_exp; 13040f66f451Sopenharmony_ci} 13050f66f451Sopenharmony_ci 13060f66f451Sopenharmony_cistatic int verifyip6_in_lease(uint8_t *nip6, uint8_t *duid, uint16_t ia_type, uint32_t iaid) 13070f66f451Sopenharmony_ci{ 13080f66f451Sopenharmony_ci static_lease6 *sls6; 13090f66f451Sopenharmony_ci struct arg_list *listdls; 13100f66f451Sopenharmony_ci 13110f66f451Sopenharmony_ci for (listdls = gstate.dleases; listdls; listdls = listdls->next) { 13120f66f451Sopenharmony_ci if (!memcmp(((dyn_lease6*) listdls->arg)->lease_nip6, nip6, sizeof(uint32_t)*4)) 13130f66f451Sopenharmony_ci return -1; 13140f66f451Sopenharmony_ci 13150f66f451Sopenharmony_ci if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len) 13160f66f451Sopenharmony_ci && ((dyn_lease6*) listdls->arg)->ia_type == ia_type) 13170f66f451Sopenharmony_ci return -1; 13180f66f451Sopenharmony_ci } 13190f66f451Sopenharmony_ci for (sls6 = gstate.leases.sleases6; sls6; sls6 = sls6->next) 13200f66f451Sopenharmony_ci if (memcmp(sls6->nip6, nip6, sizeof(uint32_t)*4)==0) return -2; 13210f66f451Sopenharmony_ci 13220f66f451Sopenharmony_ci if (memcmp(nip6, gconfig.start_ip6, sizeof(uint32_t)*4) < 0 || 13230f66f451Sopenharmony_ci memcmp(nip6, gconfig.end_ip6, sizeof(uint32_t)*4) > 0) 13240f66f451Sopenharmony_ci return -3; 13250f66f451Sopenharmony_ci 13260f66f451Sopenharmony_ci return 0; 13270f66f451Sopenharmony_ci} 13280f66f451Sopenharmony_ci 13290f66f451Sopenharmony_ci// Verify ip NIP in current leases ( assigned or not) 13300f66f451Sopenharmony_cistatic int verifyip_in_lease(uint32_t nip, uint8_t mac[6]) 13310f66f451Sopenharmony_ci{ 13320f66f451Sopenharmony_ci static_lease *sls; 13330f66f451Sopenharmony_ci struct arg_list *listdls; 13340f66f451Sopenharmony_ci 13350f66f451Sopenharmony_ci for (listdls = gstate.dleases; listdls; listdls = listdls->next) { 13360f66f451Sopenharmony_ci if (((dyn_lease*) listdls->arg)->lease_nip == nip) { 13370f66f451Sopenharmony_ci if (((int32_t)(((dyn_lease*) listdls->arg)->expires) - time(NULL)) < 0) 13380f66f451Sopenharmony_ci return 0; 13390f66f451Sopenharmony_ci return -1; 13400f66f451Sopenharmony_ci } 13410f66f451Sopenharmony_ci if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) return -1; 13420f66f451Sopenharmony_ci } 13430f66f451Sopenharmony_ci for (sls = gstate.leases.sleases; sls; sls = sls->next) 13440f66f451Sopenharmony_ci if (sls->nip == nip) return -2; 13450f66f451Sopenharmony_ci 13460f66f451Sopenharmony_ci if ((ntohl(nip) < gconfig.start_ip) || (ntohl(nip) > gconfig.end_ip)) 13470f66f451Sopenharmony_ci return -3; 13480f66f451Sopenharmony_ci 13490f66f451Sopenharmony_ci return 0; 13500f66f451Sopenharmony_ci} 13510f66f451Sopenharmony_ci 13520f66f451Sopenharmony_ci// add ip assigned_nip to dynamic lease. 13530f66f451Sopenharmony_cistatic int addip_to_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname, uint8_t update) 13540f66f451Sopenharmony_ci{ 13550f66f451Sopenharmony_ci dyn_lease *dls; 13560f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases; 13570f66f451Sopenharmony_ci uint32_t now = time(NULL); 13580f66f451Sopenharmony_ci 13590f66f451Sopenharmony_ci while (listdls) { 13600f66f451Sopenharmony_ci if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) { 13610f66f451Sopenharmony_ci if (update) *req_exp = get_lease(*req_exp + ((dyn_lease*) listdls->arg)->expires); 13620f66f451Sopenharmony_ci ((dyn_lease*) listdls->arg)->expires = *req_exp + now; 13630f66f451Sopenharmony_ci return 0; 13640f66f451Sopenharmony_ci } 13650f66f451Sopenharmony_ci listdls = listdls->next; 13660f66f451Sopenharmony_ci } 13670f66f451Sopenharmony_ci 13680f66f451Sopenharmony_ci dls = xzalloc(sizeof(dyn_lease)); 13690f66f451Sopenharmony_ci memcpy(dls->lease_mac, mac, 6); 13700f66f451Sopenharmony_ci dls->lease_nip = assigned_nip; 13710f66f451Sopenharmony_ci if (hostname) memcpy(dls->hostname, hostname, 20); 13720f66f451Sopenharmony_ci 13730f66f451Sopenharmony_ci if (update) *req_exp = get_lease(*req_exp + now); 13740f66f451Sopenharmony_ci dls->expires = *req_exp + now; 13750f66f451Sopenharmony_ci 13760f66f451Sopenharmony_ci listdls = xzalloc(sizeof(struct arg_list)); 13770f66f451Sopenharmony_ci listdls->next = gstate.dleases; 13780f66f451Sopenharmony_ci listdls->arg = (char*)dls; 13790f66f451Sopenharmony_ci gstate.dleases = listdls; 13800f66f451Sopenharmony_ci 13810f66f451Sopenharmony_ci return 0; 13820f66f451Sopenharmony_ci} 13830f66f451Sopenharmony_ci 13840f66f451Sopenharmony_cistatic int addip6_to_lease(uint8_t *assigned_nip, uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime, uint8_t update) 13850f66f451Sopenharmony_ci{ 13860f66f451Sopenharmony_ci dyn_lease6 *dls6; 13870f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases; 13880f66f451Sopenharmony_ci uint32_t now = time(NULL); 13890f66f451Sopenharmony_ci 13900f66f451Sopenharmony_ci while (listdls) { 13910f66f451Sopenharmony_ci if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)) { 13920f66f451Sopenharmony_ci if (update) *lifetime = get_lease(*lifetime + ((dyn_lease6*) listdls->arg)->expires); 13930f66f451Sopenharmony_ci ((dyn_lease6*) listdls->arg)->expires = *lifetime + now; 13940f66f451Sopenharmony_ci return 0; 13950f66f451Sopenharmony_ci } 13960f66f451Sopenharmony_ci listdls = listdls->next; 13970f66f451Sopenharmony_ci } 13980f66f451Sopenharmony_ci 13990f66f451Sopenharmony_ci dls6 = xzalloc(sizeof(dyn_lease6)); 14000f66f451Sopenharmony_ci dls6->duid_len = duid_len; 14010f66f451Sopenharmony_ci memcpy(dls6->duid, duid, duid_len); 14020f66f451Sopenharmony_ci dls6->ia_type = ia_type; 14030f66f451Sopenharmony_ci dls6->iaid = iaid; 14040f66f451Sopenharmony_ci memcpy(dls6->lease_nip6, assigned_nip, sizeof(uint32_t)*4); 14050f66f451Sopenharmony_ci 14060f66f451Sopenharmony_ci if (update) *lifetime = get_lease(*lifetime + now); 14070f66f451Sopenharmony_ci dls6->expires = *lifetime + now; 14080f66f451Sopenharmony_ci 14090f66f451Sopenharmony_ci listdls = xzalloc(sizeof(struct arg_list)); 14100f66f451Sopenharmony_ci listdls->next = gstate.dleases; 14110f66f451Sopenharmony_ci listdls->arg = (char*)dls6; 14120f66f451Sopenharmony_ci gstate.dleases = listdls; 14130f66f451Sopenharmony_ci 14140f66f451Sopenharmony_ci return 0; 14150f66f451Sopenharmony_ci} 14160f66f451Sopenharmony_ci 14170f66f451Sopenharmony_ci// delete ip assigned_nip from dynamic lease. 14180f66f451Sopenharmony_cistatic int delip_from_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t del_time) 14190f66f451Sopenharmony_ci{ 14200f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases; 14210f66f451Sopenharmony_ci 14220f66f451Sopenharmony_ci while (listdls) { 14230f66f451Sopenharmony_ci if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) { 14240f66f451Sopenharmony_ci ((dyn_lease*) listdls->arg)->expires = del_time + time(NULL); 14250f66f451Sopenharmony_ci return 0; 14260f66f451Sopenharmony_ci } 14270f66f451Sopenharmony_ci listdls = listdls->next; 14280f66f451Sopenharmony_ci } 14290f66f451Sopenharmony_ci return -1; 14300f66f451Sopenharmony_ci} 14310f66f451Sopenharmony_ci 14320f66f451Sopenharmony_ci// returns a IP from static, dynamic leases or free ip pool, 0 otherwise. 14330f66f451Sopenharmony_cistatic uint32_t getip_from_pool(uint32_t req_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname) 14340f66f451Sopenharmony_ci{ 14350f66f451Sopenharmony_ci uint32_t nip = 0; 14360f66f451Sopenharmony_ci static_lease *sls = gstate.leases.sleases; 14370f66f451Sopenharmony_ci struct arg_list *listdls = gstate.dleases, *tmp = NULL; 14380f66f451Sopenharmony_ci 14390f66f451Sopenharmony_ci if (req_nip && (!verifyip_in_lease(req_nip, mac))) nip = req_nip; 14400f66f451Sopenharmony_ci 14410f66f451Sopenharmony_ci if (!nip) { 14420f66f451Sopenharmony_ci while (listdls) { 14430f66f451Sopenharmony_ci if (!memcmp(((dyn_lease*)listdls->arg)->lease_mac, mac, 6)) { 14440f66f451Sopenharmony_ci nip = ((dyn_lease*)listdls->arg)->lease_nip; 14450f66f451Sopenharmony_ci if (tmp) tmp->next = listdls->next; 14460f66f451Sopenharmony_ci else gstate.dleases = listdls->next; 14470f66f451Sopenharmony_ci free(listdls->arg); 14480f66f451Sopenharmony_ci free(listdls); 14490f66f451Sopenharmony_ci if (verifyip_in_lease(nip, mac) < 0) nip = 0; 14500f66f451Sopenharmony_ci break; 14510f66f451Sopenharmony_ci } 14520f66f451Sopenharmony_ci tmp = listdls; 14530f66f451Sopenharmony_ci listdls = listdls->next; 14540f66f451Sopenharmony_ci } 14550f66f451Sopenharmony_ci } 14560f66f451Sopenharmony_ci if (!nip) { 14570f66f451Sopenharmony_ci while (sls) { 14580f66f451Sopenharmony_ci if (memcmp(sls->mac, mac, 6) == 0) { 14590f66f451Sopenharmony_ci nip = sls->nip; 14600f66f451Sopenharmony_ci break; 14610f66f451Sopenharmony_ci } 14620f66f451Sopenharmony_ci sls = sls->next; 14630f66f451Sopenharmony_ci } 14640f66f451Sopenharmony_ci } 14650f66f451Sopenharmony_ci if (!nip) { 14660f66f451Sopenharmony_ci for (nip = htonl(gconfig.start_ip); ntohl(nip) <= gconfig.end_ip; ) { 14670f66f451Sopenharmony_ci if (!verifyip_in_lease(nip, mac)) break; 14680f66f451Sopenharmony_ci nip = ntohl(nip); 14690f66f451Sopenharmony_ci nip = htonl(++nip); 14700f66f451Sopenharmony_ci } 14710f66f451Sopenharmony_ci if (ntohl(nip) > gconfig.end_ip) { 14720f66f451Sopenharmony_ci nip = 0; 14730f66f451Sopenharmony_ci infomsg(infomode, "can't find free IP in IP Pool."); 14740f66f451Sopenharmony_ci } 14750f66f451Sopenharmony_ci } 14760f66f451Sopenharmony_ci if (nip) addip_to_lease(nip, mac, req_exp, hostname, 1); 14770f66f451Sopenharmony_ci return nip; 14780f66f451Sopenharmony_ci} 14790f66f451Sopenharmony_ci 14800f66f451Sopenharmony_cistatic uint8_t *getip6_from_pool(uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime) 14810f66f451Sopenharmony_ci{ 14820f66f451Sopenharmony_ci static uint8_t nip6[16] = {0, }; 14830f66f451Sopenharmony_ci static_lease6 *sls6 = gstate.leases.sleases6; 14840f66f451Sopenharmony_ci struct arg_list *listdls6 = gstate.dleases, *tmp = NULL; 14850f66f451Sopenharmony_ci 14860f66f451Sopenharmony_ci while(listdls6) { 14870f66f451Sopenharmony_ci if (!memcmp(((dyn_lease6*)listdls6->arg)->duid, duid, duid_len)) { 14880f66f451Sopenharmony_ci memcpy(nip6, ((dyn_lease6*)listdls6->arg)->lease_nip6, sizeof(nip6)); 14890f66f451Sopenharmony_ci if(tmp) tmp->next = listdls6->next; 14900f66f451Sopenharmony_ci else gstate.dleases = listdls6->next; 14910f66f451Sopenharmony_ci free(listdls6->arg); 14920f66f451Sopenharmony_ci free(listdls6); 14930f66f451Sopenharmony_ci 14940f66f451Sopenharmony_ci if(verifyip6_in_lease(nip6, duid, ia_type, iaid) < 0) 14950f66f451Sopenharmony_ci memset(nip6, 0, sizeof(nip6)); 14960f66f451Sopenharmony_ci break; 14970f66f451Sopenharmony_ci } 14980f66f451Sopenharmony_ci tmp = listdls6; 14990f66f451Sopenharmony_ci listdls6 = listdls6->next; 15000f66f451Sopenharmony_ci } 15010f66f451Sopenharmony_ci 15020f66f451Sopenharmony_ci if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) { 15030f66f451Sopenharmony_ci while(sls6) { 15040f66f451Sopenharmony_ci if(!memcmp(sls6->duid, duid, 6)) { 15050f66f451Sopenharmony_ci memcpy(nip6, sls6->nip6, sizeof(nip6)); 15060f66f451Sopenharmony_ci break; 15070f66f451Sopenharmony_ci } 15080f66f451Sopenharmony_ci sls6 = sls6->next; 15090f66f451Sopenharmony_ci } 15100f66f451Sopenharmony_ci } 15110f66f451Sopenharmony_ci 15120f66f451Sopenharmony_ci if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) { 15130f66f451Sopenharmony_ci memcpy(nip6, gconfig.start_ip6, sizeof(nip6)); 15140f66f451Sopenharmony_ci while(memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) < 0) { 15150f66f451Sopenharmony_ci if(!verifyip6_in_lease(nip6, duid, ia_type, iaid)) break; 15160f66f451Sopenharmony_ci int i=sizeof(nip6); 15170f66f451Sopenharmony_ci while(i--) { 15180f66f451Sopenharmony_ci ++nip6[i]; 15190f66f451Sopenharmony_ci if (!nip6[i]) { 15200f66f451Sopenharmony_ci if(i==(sizeof(nip6)-1)) ++nip6[i]; 15210f66f451Sopenharmony_ci ++nip6[i-1]; 15220f66f451Sopenharmony_ci } else 15230f66f451Sopenharmony_ci break; 15240f66f451Sopenharmony_ci } 15250f66f451Sopenharmony_ci } 15260f66f451Sopenharmony_ci 15270f66f451Sopenharmony_ci if (memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) > 0) { 15280f66f451Sopenharmony_ci memset(nip6, 0, sizeof(nip6)); 15290f66f451Sopenharmony_ci infomsg(infomode, "can't find free IP in IPv6 Pool."); 15300f66f451Sopenharmony_ci } 15310f66f451Sopenharmony_ci } 15320f66f451Sopenharmony_ci 15330f66f451Sopenharmony_ci if(memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) { 15340f66f451Sopenharmony_ci addip6_to_lease(nip6, duid, duid_len, ia_type, iaid, lifetime, 1); 15350f66f451Sopenharmony_ci infomsg(infomode, "Assigned IPv6 %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", 15360f66f451Sopenharmony_ci nip6[0], nip6[1], nip6[2], nip6[3], nip6[4], nip6[5], nip6[6], nip6[7], nip6[8], 15370f66f451Sopenharmony_ci nip6[9], nip6[10], nip6[11], nip6[12], nip6[13], nip6[14], nip6[15]); 15380f66f451Sopenharmony_ci } 15390f66f451Sopenharmony_ci return nip6; 15400f66f451Sopenharmony_ci} 15410f66f451Sopenharmony_ci 15420f66f451Sopenharmony_cistatic void read_leasefile(void) 15430f66f451Sopenharmony_ci{ 15440f66f451Sopenharmony_ci uint32_t passed, ip; 15450f66f451Sopenharmony_ci int32_t tmp_time; 15460f66f451Sopenharmony_ci int64_t timestamp; 15470f66f451Sopenharmony_ci dyn_lease *dls; 15480f66f451Sopenharmony_ci int fd = open(gconfig.lease_file, O_RDONLY); 15490f66f451Sopenharmony_ci 15500f66f451Sopenharmony_ci dls = xzalloc(sizeof(dyn_lease)); 15510f66f451Sopenharmony_ci 15520f66f451Sopenharmony_ci if (read(fd, ×tamp, sizeof(timestamp)) != sizeof(timestamp)) 15530f66f451Sopenharmony_ci goto lease_error_exit; 15540f66f451Sopenharmony_ci 15550f66f451Sopenharmony_ci timestamp = SWAP_BE64(timestamp); 15560f66f451Sopenharmony_ci passed = time(NULL) - timestamp; 15570f66f451Sopenharmony_ci if ((uint64_t)passed > 12 * 60 * 60) goto lease_error_exit; 15580f66f451Sopenharmony_ci 15590f66f451Sopenharmony_ci while (read(fd, dls, sizeof(dyn_lease)) == sizeof(dyn_lease)) { 15600f66f451Sopenharmony_ci ip = ntohl(dls->lease_nip); 15610f66f451Sopenharmony_ci if (ip >= gconfig.start_ip && ip <= gconfig.end_ip) { 15620f66f451Sopenharmony_ci tmp_time = ntohl(dls->expires) - passed; 15630f66f451Sopenharmony_ci if (tmp_time < 0) continue; 15640f66f451Sopenharmony_ci addip_to_lease(dls->lease_nip, dls->lease_mac, 15650f66f451Sopenharmony_ci (uint32_t*)&tmp_time, dls->hostname, 0); 15660f66f451Sopenharmony_ci } 15670f66f451Sopenharmony_ci } 15680f66f451Sopenharmony_cilease_error_exit: 15690f66f451Sopenharmony_ci free(dls); 15700f66f451Sopenharmony_ci close(fd); 15710f66f451Sopenharmony_ci} 15720f66f451Sopenharmony_ci 15730f66f451Sopenharmony_cistatic void read_lease6file(void) 15740f66f451Sopenharmony_ci{ 15750f66f451Sopenharmony_ci uint32_t passed; 15760f66f451Sopenharmony_ci uint32_t tmp_time; 15770f66f451Sopenharmony_ci int64_t timestamp; 15780f66f451Sopenharmony_ci dyn_lease6 *dls6; 15790f66f451Sopenharmony_ci int fd = open(gconfig.lease6_file, O_RDONLY); 15800f66f451Sopenharmony_ci 15810f66f451Sopenharmony_ci dls6 = xzalloc(sizeof(dyn_lease6)); 15820f66f451Sopenharmony_ci 15830f66f451Sopenharmony_ci if (read(fd, ×tamp, sizeof(timestamp)) != sizeof(timestamp)) 15840f66f451Sopenharmony_ci goto lease6_error_exit; 15850f66f451Sopenharmony_ci 15860f66f451Sopenharmony_ci timestamp = SWAP_BE64(timestamp); 15870f66f451Sopenharmony_ci passed = time(NULL) - timestamp; 15880f66f451Sopenharmony_ci if ((uint64_t)passed > 12 * 60 * 60) goto lease6_error_exit; 15890f66f451Sopenharmony_ci 15900f66f451Sopenharmony_ci while (read(fd, dls6, sizeof(dyn_lease6)) == sizeof(dyn_lease6)) { 15910f66f451Sopenharmony_ci if (memcmp(dls6->lease_nip6, gconfig.start_ip6, sizeof(uint32_t)*4) > 0 && 15920f66f451Sopenharmony_ci memcmp(dls6->lease_nip6, gconfig.end_ip6, sizeof(uint32_t)*4) < 0) { 15930f66f451Sopenharmony_ci tmp_time = ntohl(dls6->expires) - passed; 15940f66f451Sopenharmony_ci if (tmp_time < 0U) continue; 15950f66f451Sopenharmony_ci addip6_to_lease(dls6->lease_nip6, dls6->duid, dls6->duid_len, dls6->ia_type, dls6->iaid, 15960f66f451Sopenharmony_ci (uint32_t*)&tmp_time, 0); 15970f66f451Sopenharmony_ci } 15980f66f451Sopenharmony_ci } 15990f66f451Sopenharmony_ci 16000f66f451Sopenharmony_cilease6_error_exit: 16010f66f451Sopenharmony_ci free(dls6); 16020f66f451Sopenharmony_ci close(fd); 16030f66f451Sopenharmony_ci} 16040f66f451Sopenharmony_ci 16050f66f451Sopenharmony_civoid dhcpd_main(void) 16060f66f451Sopenharmony_ci{ 16070f66f451Sopenharmony_ci struct timeval tv; 16080f66f451Sopenharmony_ci int retval, i; 16090f66f451Sopenharmony_ci uint8_t *optptr, msgtype = 0; 16100f66f451Sopenharmony_ci uint16_t optlen = 0; 16110f66f451Sopenharmony_ci uint32_t waited = 0, serverid = 0, requested_nip = 0; 16120f66f451Sopenharmony_ci uint8_t transactionid[3] = {0,}; 16130f66f451Sopenharmony_ci uint32_t reqested_lease = 0, ip_pool_size = 0; 16140f66f451Sopenharmony_ci char *hstname = NULL; 16150f66f451Sopenharmony_ci fd_set rfds; 16160f66f451Sopenharmony_ci 16170f66f451Sopenharmony_ci infomode = LOG_CONSOLE; 16180f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_f)) { 16190f66f451Sopenharmony_ci daemon(0,0); 16200f66f451Sopenharmony_ci infomode = LOG_SILENT; 16210f66f451Sopenharmony_ci } 16220f66f451Sopenharmony_ci if (toys.optflags & FLAG_S) { 16230f66f451Sopenharmony_ci openlog("UDHCPD :", LOG_PID, LOG_DAEMON); 16240f66f451Sopenharmony_ci infomode |= LOG_SYSTEM; 16250f66f451Sopenharmony_ci } 16260f66f451Sopenharmony_ci setlinebuf(stdout); 16270f66f451Sopenharmony_ci //DHCPD_CONF_FILE 16280f66f451Sopenharmony_ci parse_server_config((toys.optc==1)?toys.optargs[0]:"/etc/dhcpd.conf", keywords); 16290f66f451Sopenharmony_ci infomsg(infomode, "toybox dhcpd started"); 16300f66f451Sopenharmony_ci 16310f66f451Sopenharmony_ci if (toys.optflags & FLAG_6){ 16320f66f451Sopenharmony_ci addr_version = AF_INET6; 16330f66f451Sopenharmony_ci gconfig.t1 = ntohl(gconfig.t1); 16340f66f451Sopenharmony_ci gconfig.t2 = ntohl(gconfig.t2); 16350f66f451Sopenharmony_ci gconfig.pref_lifetime = ntohl(gconfig.pref_lifetime); 16360f66f451Sopenharmony_ci gconfig.valid_lifetime = ntohl(gconfig.valid_lifetime); 16370f66f451Sopenharmony_ci gconfig.port = 547; 16380f66f451Sopenharmony_ci for(i=0;i<4;i++) 16390f66f451Sopenharmony_ci ip_pool_size += (gconfig.end_ip6[i]-gconfig.start_ip6[i])<<((3-i)*8); 16400f66f451Sopenharmony_ci } else { 16410f66f451Sopenharmony_ci gconfig.start_ip = ntohl(gconfig.start_ip); 16420f66f451Sopenharmony_ci gconfig.end_ip = ntohl(gconfig.end_ip); 16430f66f451Sopenharmony_ci ip_pool_size = gconfig.end_ip - gconfig.start_ip + 1; 16440f66f451Sopenharmony_ci } 16450f66f451Sopenharmony_ci 16460f66f451Sopenharmony_ci if (gconfig.max_leases > ip_pool_size) { 16470f66f451Sopenharmony_ci error_msg("max_leases=%u is too big, setting to %u", 16480f66f451Sopenharmony_ci (unsigned) gconfig.max_leases, ip_pool_size); 16490f66f451Sopenharmony_ci gconfig.max_leases = ip_pool_size; 16500f66f451Sopenharmony_ci } 16510f66f451Sopenharmony_ci write_pid(gconfig.pidfile); 16520f66f451Sopenharmony_ci set_maxlease(); 16530f66f451Sopenharmony_ci if(TT.iface) gconfig.interface = TT.iface; 16540f66f451Sopenharmony_ci if(TT.port) gconfig.port = TT.port; 16550f66f451Sopenharmony_ci (addr_version==AF_INET6) ? read_lease6file() : read_leasefile(); 16560f66f451Sopenharmony_ci 16570f66f451Sopenharmony_ci 16580f66f451Sopenharmony_ci if (get_interface(gconfig.interface, &gconfig.ifindex, 16590f66f451Sopenharmony_ci (addr_version==AF_INET6)? (void*)gconfig.server_nip6 : 16600f66f451Sopenharmony_ci (void*)&gconfig.server_nip, gconfig.server_mac) < 0) 16610f66f451Sopenharmony_ci perror_exit("Failed to get interface %s", gconfig.interface); 16620f66f451Sopenharmony_ci setup_signal(); 16630f66f451Sopenharmony_ci if (addr_version==AF_INET6) { 16640f66f451Sopenharmony_ci open_listensock6(); 16650f66f451Sopenharmony_ci } else { 16660f66f451Sopenharmony_ci gconfig.server_nip = htonl(gconfig.server_nip); 16670f66f451Sopenharmony_ci open_listensock(); 16680f66f451Sopenharmony_ci } 16690f66f451Sopenharmony_ci 16700f66f451Sopenharmony_ci fcntl(gstate.listensock, F_SETFD, FD_CLOEXEC); 16710f66f451Sopenharmony_ci 16720f66f451Sopenharmony_ci for (;;) { 16730f66f451Sopenharmony_ci uint32_t timestmp = time(NULL); 16740f66f451Sopenharmony_ci FD_ZERO(&rfds); 16750f66f451Sopenharmony_ci FD_SET(gstate.listensock, &rfds); 16760f66f451Sopenharmony_ci FD_SET(sigfd.rd, &rfds); 16770f66f451Sopenharmony_ci tv.tv_sec = gconfig.auto_time - waited; 16780f66f451Sopenharmony_ci tv.tv_usec = 0; 16790f66f451Sopenharmony_ci retval = 0; 16800f66f451Sopenharmony_ci serverid = 0; 16810f66f451Sopenharmony_ci msgtype = 0; 16820f66f451Sopenharmony_ci 16830f66f451Sopenharmony_ci int maxfd = (sigfd.rd > gstate.listensock)? sigfd.rd : gstate.listensock; 16840f66f451Sopenharmony_ci dbg("select waiting ....\n"); 16850f66f451Sopenharmony_ci retval = select(maxfd + 1, &rfds, NULL, NULL, (gconfig.auto_time?&tv:NULL)); 16860f66f451Sopenharmony_ci if (retval < 0) { 16870f66f451Sopenharmony_ci if (errno == EINTR) { 16880f66f451Sopenharmony_ci waited += (unsigned) time(NULL) - timestmp; 16890f66f451Sopenharmony_ci continue; 16900f66f451Sopenharmony_ci } 16910f66f451Sopenharmony_ci dbg("Error in select wait again...\n"); 16920f66f451Sopenharmony_ci continue; 16930f66f451Sopenharmony_ci } 16940f66f451Sopenharmony_ci if (!retval) { // Timed out 16950f66f451Sopenharmony_ci dbg("select wait Timed Out...\n"); 16960f66f451Sopenharmony_ci waited = 0; 16970f66f451Sopenharmony_ci (addr_version == AF_INET6)? write_lease6file() : write_leasefile(); 16980f66f451Sopenharmony_ci if (get_interface(gconfig.interface, &gconfig.ifindex, 16990f66f451Sopenharmony_ci (addr_version==AF_INET6)? (void*)gconfig.server_nip6 : 17000f66f451Sopenharmony_ci (void*)&gconfig.server_nip, gconfig.server_mac)<0) 17010f66f451Sopenharmony_ci perror_exit("Failed to get interface %s", gconfig.interface); 17020f66f451Sopenharmony_ci if(addr_version != AF_INET6) { 17030f66f451Sopenharmony_ci gconfig.server_nip = htonl(gconfig.server_nip); 17040f66f451Sopenharmony_ci } 17050f66f451Sopenharmony_ci continue; 17060f66f451Sopenharmony_ci } 17070f66f451Sopenharmony_ci if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal 17080f66f451Sopenharmony_ci unsigned char sig; 17090f66f451Sopenharmony_ci if (read(sigfd.rd, &sig, 1) != 1) { 17100f66f451Sopenharmony_ci dbg("signal read failed.\n"); 17110f66f451Sopenharmony_ci continue; 17120f66f451Sopenharmony_ci } 17130f66f451Sopenharmony_ci switch (sig) { 17140f66f451Sopenharmony_ci case SIGUSR1: 17150f66f451Sopenharmony_ci infomsg(infomode, "Received SIGUSR1"); 17160f66f451Sopenharmony_ci (addr_version==AF_INET6)? write_lease6file() : write_leasefile(); 17170f66f451Sopenharmony_ci continue; 17180f66f451Sopenharmony_ci case SIGTERM: 17190f66f451Sopenharmony_ci infomsg(infomode, "received sigterm"); 17200f66f451Sopenharmony_ci (addr_version==AF_INET6)? write_lease6file() : write_leasefile(); 17210f66f451Sopenharmony_ci unlink(gconfig.pidfile); 17220f66f451Sopenharmony_ci exit(0); 17230f66f451Sopenharmony_ci break; 17240f66f451Sopenharmony_ci default: break; 17250f66f451Sopenharmony_ci } 17260f66f451Sopenharmony_ci } 17270f66f451Sopenharmony_ci if (FD_ISSET(gstate.listensock, &rfds)) { // Some Activity on RDFDs : is socket 17280f66f451Sopenharmony_ci dbg("select listen sock read\n"); 17290f66f451Sopenharmony_ci if(addr_version==AF_INET6) { 17300f66f451Sopenharmony_ci void *client_duid, *server_duid, *client_ia_na, *server_ia_na, 17310f66f451Sopenharmony_ci *client_ia_pd; 17320f66f451Sopenharmony_ci uint8_t client_lla[6] = {0,}; 17330f66f451Sopenharmony_ci uint16_t client_duid_len = 0, server_duid_len = 0, server_ia_na_len = 0, 17340f66f451Sopenharmony_ci client_ia_na_len = 0, client_ia_pd_len = 0; 17350f66f451Sopenharmony_ci 17360f66f451Sopenharmony_ci if(read_packet6() < 0) { 17370f66f451Sopenharmony_ci open_listensock6(); 17380f66f451Sopenharmony_ci continue; 17390f66f451Sopenharmony_ci } 17400f66f451Sopenharmony_ci waited += time(NULL) - timestmp; 17410f66f451Sopenharmony_ci 17420f66f451Sopenharmony_ci memcpy(&gstate.rqcode, &gstate.rcvd.rcvd_pkt6.msgtype, sizeof(uint8_t)); 17430f66f451Sopenharmony_ci memcpy(&transactionid, &gstate.rcvd.rcvd_pkt6.transaction_id, 17440f66f451Sopenharmony_ci sizeof(transactionid)); 17450f66f451Sopenharmony_ci 17460f66f451Sopenharmony_ci if (!gstate.rqcode || gstate.rqcode < DHCP6SOLICIT || 17470f66f451Sopenharmony_ci gstate.rqcode > DHCP6RELAYREPLY) { 17480f66f451Sopenharmony_ci dbg("no or bad message type option, ignoring packet.\n"); 17490f66f451Sopenharmony_ci continue; 17500f66f451Sopenharmony_ci } 17510f66f451Sopenharmony_ci if (memcmp(gstate.rcvd.rcvd_pkt6.transaction_id, transactionid, 3)) { 17520f66f451Sopenharmony_ci dbg("no or bad transaction id, ignoring packet.\n"); 17530f66f451Sopenharmony_ci continue; 17540f66f451Sopenharmony_ci } 17550f66f451Sopenharmony_ci 17560f66f451Sopenharmony_ci waited += time(NULL) - timestmp; 17570f66f451Sopenharmony_ci switch (gstate.rqcode) { 17580f66f451Sopenharmony_ci case DHCP6SOLICIT: 17590f66f451Sopenharmony_ci dbg("Message Type: DHCP6SOLICIT\n"); 17600f66f451Sopenharmony_ci optptr = prepare_send_pkt6(DHCP6ADVERTISE); 17610f66f451Sopenharmony_ci optlen = 0; 17620f66f451Sopenharmony_ci 17630f66f451Sopenharmony_ci //TODO policy check 17640f66f451Sopenharmony_ci //TODO Receive: ORO check (e.g. DNS) 17650f66f451Sopenharmony_ci 17660f66f451Sopenharmony_ci //Receive: Client Identifier (DUID) 17670f66f451Sopenharmony_ci get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 17680f66f451Sopenharmony_ci DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid); 17690f66f451Sopenharmony_ci 17700f66f451Sopenharmony_ci //Receive: Identity Association for Non-temporary Address 17710f66f451Sopenharmony_ci if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 17720f66f451Sopenharmony_ci DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) { 17730f66f451Sopenharmony_ci uint16_t ia_addr_len = sizeof(struct optval_ia_addr); 17740f66f451Sopenharmony_ci void *ia_addr, *status_code; 17750f66f451Sopenharmony_ci char *status_code_msg; 17760f66f451Sopenharmony_ci uint16_t status_code_len = 0; 17770f66f451Sopenharmony_ci server_ia_na_len = sizeof(struct optval_ia_na); 17780f66f451Sopenharmony_ci 17790f66f451Sopenharmony_ci //IA Address 17800f66f451Sopenharmony_ci ia_addr = xzalloc(ia_addr_len); 17810f66f451Sopenharmony_ci struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr; 17820f66f451Sopenharmony_ci (*ia_addr_p).pref_lifetime = gconfig.pref_lifetime; 17830f66f451Sopenharmony_ci (*ia_addr_p).valid_lifetime = gconfig.valid_lifetime; 17840f66f451Sopenharmony_ci memcpy(&(*ia_addr_p).ipv6_addr, 17850f66f451Sopenharmony_ci getip6_from_pool(client_duid, client_duid_len, 17860f66f451Sopenharmony_ci DHCP6_OPT_IA_NA, (*(struct optval_ia_na*) client_ia_na).iaid, 17870f66f451Sopenharmony_ci &(*ia_addr_p).pref_lifetime), sizeof(uint32_t)*4); 17880f66f451Sopenharmony_ci server_ia_na_len += (ia_addr_len+4); 17890f66f451Sopenharmony_ci 17900f66f451Sopenharmony_ci //Status Code 17910f66f451Sopenharmony_ci if(memcmp((*ia_addr_p).ipv6_addr, (uint8_t[16]){0}, sizeof(uint32_t)*4)) { 17920f66f451Sopenharmony_ci status_code_msg = xstrdup("Assigned an address."); 17930f66f451Sopenharmony_ci status_code_len = strlen(status_code_msg)+1; 17940f66f451Sopenharmony_ci status_code = xzalloc(status_code_len); 17950f66f451Sopenharmony_ci struct optval_status_code *status_code_p = 17960f66f451Sopenharmony_ci (struct optval_status_code*)status_code; 17970f66f451Sopenharmony_ci (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS); 17980f66f451Sopenharmony_ci memcpy((*status_code_p).status_msg, status_code_msg, 17990f66f451Sopenharmony_ci status_code_len); 18000f66f451Sopenharmony_ci server_ia_na_len += (status_code_len+4); 18010f66f451Sopenharmony_ci free(status_code_msg); 18020f66f451Sopenharmony_ci } else { 18030f66f451Sopenharmony_ci status_code_msg = xstrdup("There's no available address."); 18040f66f451Sopenharmony_ci status_code_len = strlen(status_code_msg)+1; 18050f66f451Sopenharmony_ci status_code = xzalloc(status_code_len); 18060f66f451Sopenharmony_ci struct optval_status_code *status_code_p = 18070f66f451Sopenharmony_ci (struct optval_status_code*)status_code; 18080f66f451Sopenharmony_ci (*status_code_p).status_code = htons(DHCP6_STATUS_NOADDRSAVAIL); 18090f66f451Sopenharmony_ci memcpy((*status_code_p).status_msg, status_code_msg, 18100f66f451Sopenharmony_ci status_code_len); 18110f66f451Sopenharmony_ci server_ia_na_len += (status_code_len+4); 18120f66f451Sopenharmony_ci server_ia_na_len -= (ia_addr_len+4); 18130f66f451Sopenharmony_ci ia_addr_len = 0; 18140f66f451Sopenharmony_ci free(ia_addr); 18150f66f451Sopenharmony_ci free(status_code_msg); 18160f66f451Sopenharmony_ci //TODO send failed status code 18170f66f451Sopenharmony_ci break; 18180f66f451Sopenharmony_ci } 18190f66f451Sopenharmony_ci 18200f66f451Sopenharmony_ci //combine options 18210f66f451Sopenharmony_ci server_ia_na = xzalloc(server_ia_na_len); 18220f66f451Sopenharmony_ci struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na; 18230f66f451Sopenharmony_ci (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid; 18240f66f451Sopenharmony_ci (*ia_na_p).t1 = gconfig.t1; 18250f66f451Sopenharmony_ci (*ia_na_p).t2 = gconfig.t2; 18260f66f451Sopenharmony_ci 18270f66f451Sopenharmony_ci uint8_t* ia_na_optptr = (*ia_na_p).optval; 18280f66f451Sopenharmony_ci if(ia_addr_len) { 18290f66f451Sopenharmony_ci set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, ia_addr, ia_addr_len); 18300f66f451Sopenharmony_ci ia_na_optptr += (ia_addr_len + 4); 18310f66f451Sopenharmony_ci free(ia_addr); 18320f66f451Sopenharmony_ci } 18330f66f451Sopenharmony_ci if(status_code_len) { 18340f66f451Sopenharmony_ci set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, status_code, 18350f66f451Sopenharmony_ci status_code_len); 18360f66f451Sopenharmony_ci ia_na_optptr += (status_code_len); 18370f66f451Sopenharmony_ci free(status_code); 18380f66f451Sopenharmony_ci } 18390f66f451Sopenharmony_ci 18400f66f451Sopenharmony_ci //Response: Identity Association for Non-temporary Address 18410f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, server_ia_na, 18420f66f451Sopenharmony_ci server_ia_na_len); 18430f66f451Sopenharmony_ci optlen += (server_ia_na_len + 4); 18440f66f451Sopenharmony_ci free(client_ia_na);free(server_ia_na); 18450f66f451Sopenharmony_ci } 18460f66f451Sopenharmony_ci //Receive: Identity Association for Prefix Delegation 18470f66f451Sopenharmony_ci else if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 18480f66f451Sopenharmony_ci DHCP6_OPT_IA_PD, &client_ia_pd_len, &client_ia_pd)) { 18490f66f451Sopenharmony_ci 18500f66f451Sopenharmony_ci //TODO 18510f66f451Sopenharmony_ci //Response: Identity Association for Prefix Delegation 18520f66f451Sopenharmony_ci } 18530f66f451Sopenharmony_ci 18540f66f451Sopenharmony_ci //DUID type: link-layer address plus time 18550f66f451Sopenharmony_ci if(ntohs((*(struct optval_duid_llt*)client_duid).type) == 18560f66f451Sopenharmony_ci DHCP6_DUID_LLT) { 18570f66f451Sopenharmony_ci server_duid_len = 8+sizeof(gconfig.server_mac); 18580f66f451Sopenharmony_ci server_duid = xzalloc(server_duid_len); 18590f66f451Sopenharmony_ci struct optval_duid_llt *server_duid_p = 18600f66f451Sopenharmony_ci (struct optval_duid_llt*)server_duid; 18610f66f451Sopenharmony_ci (*server_duid_p).type = htons(1); 18620f66f451Sopenharmony_ci (*server_duid_p).hwtype = htons(1); 18630f66f451Sopenharmony_ci (*server_duid_p).time = htonl((uint32_t) 18640f66f451Sopenharmony_ci (time(NULL) - 946684800) & 0xffffffff); 18650f66f451Sopenharmony_ci memcpy((*server_duid_p).lladdr, gconfig.server_mac, 18660f66f451Sopenharmony_ci sizeof(gconfig.server_mac)); 18670f66f451Sopenharmony_ci memcpy(&client_lla, (*(struct optval_duid_llt*)client_duid).lladdr, 18680f66f451Sopenharmony_ci sizeof(client_lla)); 18690f66f451Sopenharmony_ci 18700f66f451Sopenharmony_ci //Response: Server Identifier (DUID) 18710f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, server_duid, 18720f66f451Sopenharmony_ci server_duid_len); 18730f66f451Sopenharmony_ci optlen += (server_duid_len + 4); 18740f66f451Sopenharmony_ci //Response: Client Identifier 18750f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid, 18760f66f451Sopenharmony_ci client_duid_len); 18770f66f451Sopenharmony_ci optlen += (client_duid_len + 4); 18780f66f451Sopenharmony_ci free(client_duid);free(server_duid); 18790f66f451Sopenharmony_ci } 18800f66f451Sopenharmony_ci 18810f66f451Sopenharmony_ci send_packet6(0, client_lla, optlen); 18820f66f451Sopenharmony_ci write_lease6file(); 18830f66f451Sopenharmony_ci break; 18840f66f451Sopenharmony_ci case DHCP6REQUEST: 18850f66f451Sopenharmony_ci dbg("Message Type: DHCP6REQUEST\n"); 18860f66f451Sopenharmony_ci optptr = prepare_send_pkt6(DHCP6REPLY); 18870f66f451Sopenharmony_ci optlen = 0; 18880f66f451Sopenharmony_ci 18890f66f451Sopenharmony_ci //Receive: Client Identifier (DUID) 18900f66f451Sopenharmony_ci get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 18910f66f451Sopenharmony_ci DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid); 18920f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid, 18930f66f451Sopenharmony_ci client_duid_len); 18940f66f451Sopenharmony_ci optlen += (client_duid_len + 4); 18950f66f451Sopenharmony_ci memcpy(client_lla, (*(struct optval_duid_llt*)client_duid).lladdr, 18960f66f451Sopenharmony_ci sizeof(client_lla)); 18970f66f451Sopenharmony_ci 18980f66f451Sopenharmony_ci //Receive: Identity Association for Non-temporary Address 18990f66f451Sopenharmony_ci if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 19000f66f451Sopenharmony_ci DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) { 19010f66f451Sopenharmony_ci uint16_t ia_addr_len = 0, status_code_len = 0; 19020f66f451Sopenharmony_ci void *ia_addr, *status_code; 19030f66f451Sopenharmony_ci uint16_t server_ia_na_len = sizeof(struct optval_ia_na); 19040f66f451Sopenharmony_ci char *status_code_msg; 19050f66f451Sopenharmony_ci 19060f66f451Sopenharmony_ci //Check IA Address 19070f66f451Sopenharmony_ci get_optval6((uint8_t*)(*(struct optval_ia_na*)client_ia_na).optval, 19080f66f451Sopenharmony_ci DHCP6_OPT_IA_ADDR, &ia_addr_len, &ia_addr); 19090f66f451Sopenharmony_ci struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr; 19100f66f451Sopenharmony_ci if(verifyip6_in_lease((*ia_addr_p).ipv6_addr, client_duid, 19110f66f451Sopenharmony_ci DHCP6_OPT_IA_NA, (*(struct optval_ia_na*)client_ia_na).iaid) 19120f66f451Sopenharmony_ci == -1) { 19130f66f451Sopenharmony_ci server_ia_na_len += (ia_addr_len + 4); 19140f66f451Sopenharmony_ci //Add Status Code 19150f66f451Sopenharmony_ci status_code_msg = xstrdup("Assigned an address."); 19160f66f451Sopenharmony_ci status_code_len = strlen(status_code_msg) + 1; 19170f66f451Sopenharmony_ci status_code = xzalloc(status_code_len); 19180f66f451Sopenharmony_ci struct optval_status_code *status_code_p = 19190f66f451Sopenharmony_ci (struct optval_status_code*)status_code; 19200f66f451Sopenharmony_ci (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS); 19210f66f451Sopenharmony_ci memcpy((*status_code_p).status_msg, status_code_msg, 19220f66f451Sopenharmony_ci status_code_len); 19230f66f451Sopenharmony_ci server_ia_na_len += (status_code_len+4); 19240f66f451Sopenharmony_ci } else { 19250f66f451Sopenharmony_ci //TODO send failed status code 19260f66f451Sopenharmony_ci break; 19270f66f451Sopenharmony_ci } 19280f66f451Sopenharmony_ci 19290f66f451Sopenharmony_ci //combine options 19300f66f451Sopenharmony_ci server_ia_na = xzalloc(server_ia_na_len); 19310f66f451Sopenharmony_ci struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na; 19320f66f451Sopenharmony_ci (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid; 19330f66f451Sopenharmony_ci (*ia_na_p).t1 = gconfig.t1; 19340f66f451Sopenharmony_ci (*ia_na_p).t2 = gconfig.t2; 19350f66f451Sopenharmony_ci 19360f66f451Sopenharmony_ci uint8_t* ia_na_optptr = (*ia_na_p).optval; 19370f66f451Sopenharmony_ci ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, 19380f66f451Sopenharmony_ci ia_addr, ia_addr_len); 19390f66f451Sopenharmony_ci free(ia_addr); 19400f66f451Sopenharmony_ci 19410f66f451Sopenharmony_ci if(status_code_len) { 19420f66f451Sopenharmony_ci ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, 19430f66f451Sopenharmony_ci status_code, status_code_len); 19440f66f451Sopenharmony_ci free(status_code); 19450f66f451Sopenharmony_ci } 19460f66f451Sopenharmony_ci 19470f66f451Sopenharmony_ci //Response: Identity Association for Non-temporary Address 19480f66f451Sopenharmony_ci //(Status Code added) 19490f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, 19500f66f451Sopenharmony_ci server_ia_na, server_ia_na_len); 19510f66f451Sopenharmony_ci optlen += (server_ia_na_len + 4); 19520f66f451Sopenharmony_ci free(client_ia_na);free(server_ia_na); 19530f66f451Sopenharmony_ci } 19540f66f451Sopenharmony_ci 19550f66f451Sopenharmony_ci //Receive: Server Identifier (DUID) 19560f66f451Sopenharmony_ci get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options, 19570f66f451Sopenharmony_ci DHCP6_OPT_SERVERID, &server_duid_len, &server_duid); 19580f66f451Sopenharmony_ci optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, 19590f66f451Sopenharmony_ci server_duid, server_duid_len); 19600f66f451Sopenharmony_ci optlen += (server_duid_len + 4); 19610f66f451Sopenharmony_ci 19620f66f451Sopenharmony_ci free(client_duid); free(server_duid); 19630f66f451Sopenharmony_ci 19640f66f451Sopenharmony_ci send_packet6(0, client_lla, optlen); 19650f66f451Sopenharmony_ci write_lease6file(); 19660f66f451Sopenharmony_ci break; 19670f66f451Sopenharmony_ci case DHCP6DECLINE: //TODO 19680f66f451Sopenharmony_ci case DHCP6RENEW: //TODO 19690f66f451Sopenharmony_ci case DHCP6REBIND: //TODO 19700f66f451Sopenharmony_ci case DHCP6RELEASE: 19710f66f451Sopenharmony_ci dbg("Message Type: DHCP6RELEASE\n"); 19720f66f451Sopenharmony_ci optptr = prepare_send_pkt6(DHCP6REPLY); 19730f66f451Sopenharmony_ci break; 19740f66f451Sopenharmony_ci default: 19750f66f451Sopenharmony_ci dbg("Message Type : %u\n", gstate.rqcode); 19760f66f451Sopenharmony_ci break; 19770f66f451Sopenharmony_ci } 19780f66f451Sopenharmony_ci 19790f66f451Sopenharmony_ci } else { 19800f66f451Sopenharmony_ci if(read_packet() < 0) { 19810f66f451Sopenharmony_ci open_listensock(); 19820f66f451Sopenharmony_ci continue; 19830f66f451Sopenharmony_ci } 19840f66f451Sopenharmony_ci waited += time(NULL) - timestmp; 19850f66f451Sopenharmony_ci 19860f66f451Sopenharmony_ci get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.options, 19870f66f451Sopenharmony_ci DHCP_OPT_MESSAGE_TYPE, &gstate.rqcode); 19880f66f451Sopenharmony_ci if (gstate.rqcode == 0 || gstate.rqcode < DHCPDISCOVER 19890f66f451Sopenharmony_ci || gstate.rqcode > DHCPINFORM) { 19900f66f451Sopenharmony_ci dbg("no or bad message type option, ignoring packet.\n"); 19910f66f451Sopenharmony_ci continue; 19920f66f451Sopenharmony_ci } 19930f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 19940f66f451Sopenharmony_ci DHCP_OPT_SERVER_ID, &serverid); 19950f66f451Sopenharmony_ci if (serverid && (serverid != gconfig.server_nip)) { 19960f66f451Sopenharmony_ci dbg("server ID doesn't match, ignoring packet.\n"); 19970f66f451Sopenharmony_ci continue; 19980f66f451Sopenharmony_ci } 19990f66f451Sopenharmony_ci 20000f66f451Sopenharmony_ci waited += time(NULL) - timestmp; 20010f66f451Sopenharmony_ci switch (gstate.rqcode) { 20020f66f451Sopenharmony_ci case DHCPDISCOVER: 20030f66f451Sopenharmony_ci msgtype = DHCPOFFER; 20040f66f451Sopenharmony_ci dbg("Message Type : DHCPDISCOVER\n"); 20050f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20060f66f451Sopenharmony_ci DHCP_OPT_REQUESTED_IP, &requested_nip); 20070f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20080f66f451Sopenharmony_ci DHCP_OPT_HOST_NAME, &hstname); 20090f66f451Sopenharmony_ci reqested_lease = gconfig.offer_time; 20100f66f451Sopenharmony_ci get_reqparam(&gstate.rqopt); 20110f66f451Sopenharmony_ci optptr = prepare_send_pkt(); 20120f66f451Sopenharmony_ci gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip, 20130f66f451Sopenharmony_ci gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname); 20140f66f451Sopenharmony_ci if(!gstate.send.send_pkt.yiaddr){ 20150f66f451Sopenharmony_ci msgtype = DHCPNAK; 20160f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1); 20170f66f451Sopenharmony_ci send_packet(1); 20180f66f451Sopenharmony_ci break; 20190f66f451Sopenharmony_ci } 20200f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20210f66f451Sopenharmony_ci DHCP_OPT_LEASE_TIME, &reqested_lease); 20220f66f451Sopenharmony_ci reqested_lease = htonl(get_lease(reqested_lease + time(NULL))); 20230f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1); 20240f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4); 20250f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4); 20260f66f451Sopenharmony_ci optptr = set_reqparam(optptr, gstate.rqopt); 20270f66f451Sopenharmony_ci send_packet(1); 20280f66f451Sopenharmony_ci break; 20290f66f451Sopenharmony_ci case DHCPREQUEST: 20300f66f451Sopenharmony_ci msgtype = DHCPACK; 20310f66f451Sopenharmony_ci dbg("Message Type : DHCPREQUEST\n"); 20320f66f451Sopenharmony_ci optptr = prepare_send_pkt(); 20330f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20340f66f451Sopenharmony_ci DHCP_OPT_REQUESTED_IP, &requested_nip); 20350f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20360f66f451Sopenharmony_ci DHCP_OPT_LEASE_TIME, &reqested_lease); 20370f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20380f66f451Sopenharmony_ci DHCP_OPT_HOST_NAME, &hstname); 20390f66f451Sopenharmony_ci gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip, 20400f66f451Sopenharmony_ci gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname); 20410f66f451Sopenharmony_ci if (!serverid) reqested_lease = gconfig.max_lease_sec; 20420f66f451Sopenharmony_ci if (!gstate.send.send_pkt.yiaddr) { 20430f66f451Sopenharmony_ci msgtype = DHCPNAK; 20440f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1); 20450f66f451Sopenharmony_ci send_packet(1); 20460f66f451Sopenharmony_ci break; 20470f66f451Sopenharmony_ci } 20480f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1); 20490f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4); 20500f66f451Sopenharmony_ci reqested_lease = htonl(reqested_lease); 20510f66f451Sopenharmony_ci optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4); 20520f66f451Sopenharmony_ci send_packet(1); 20530f66f451Sopenharmony_ci write_leasefile(); 20540f66f451Sopenharmony_ci break; 20550f66f451Sopenharmony_ci case DHCPDECLINE:// FALL THROUGH 20560f66f451Sopenharmony_ci case DHCPRELEASE: 20570f66f451Sopenharmony_ci dbg("Message Type : DHCPDECLINE or DHCPRELEASE \n"); 20580f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20590f66f451Sopenharmony_ci DHCP_OPT_SERVER_ID, &serverid); 20600f66f451Sopenharmony_ci if (serverid != gconfig.server_nip) break; 20610f66f451Sopenharmony_ci get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options, 20620f66f451Sopenharmony_ci DHCP_OPT_REQUESTED_IP, &requested_nip); 20630f66f451Sopenharmony_ci delip_from_lease(requested_nip, gstate.rcvd.rcvd_pkt.chaddr, 20640f66f451Sopenharmony_ci (gstate.rqcode==DHCPRELEASE)?0:gconfig.decline_time); 20650f66f451Sopenharmony_ci break; 20660f66f451Sopenharmony_ci default: 20670f66f451Sopenharmony_ci dbg("Message Type : %u\n", gstate.rqcode); 20680f66f451Sopenharmony_ci break; 20690f66f451Sopenharmony_ci } 20700f66f451Sopenharmony_ci } 20710f66f451Sopenharmony_ci } 20720f66f451Sopenharmony_ci } 20730f66f451Sopenharmony_ci} 2074