From 0fb45e10d2d490c5f74b197009615d9fb5fe7482 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 20 Nov 2023 21:54:14 +0900 Subject: [PATCH] added many dhcp message functions --- lib/Makefile.am | 1 + lib/Makefile.in | 79 ++++++----- lib/dhcp-msg.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/hio-dhcp.h | 247 ++++++++++++++++++++++++++++++++- 4 files changed, 640 insertions(+), 41 deletions(-) create mode 100644 lib/dhcp-msg.c diff --git a/lib/Makefile.am b/lib/Makefile.am index 938ddb4..21d8170 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -71,6 +71,7 @@ lib_LTLIBRARIES = libhio.la libhio_la_SOURCES = \ chr.c \ dhcp-svr.c \ + dhcp-msg.c \ dns.c \ dns-cli.c \ ecs.c \ diff --git a/lib/Makefile.in b/lib/Makefile.in index 3de4bcf..c6b0c3f 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -147,34 +147,34 @@ am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libhio_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) -am__libhio_la_SOURCES_DIST = chr.c dhcp-svr.c dns.c dns-cli.c ecs.c \ - ecs-imp.h err.c fcgi-cli.c fmt.c fmt-imp.h htb.c htrd.c htre.c \ - http.c http-cgi.c http-fcgi.c http-file.c http-prv.h \ - http-prxy.c http-svr.c http-thr.c http-txt.c json.c hio-prv.h \ - hio.c md5.c nwif.c opt.c opt-imp.h path.c pipe.c pro.c pty.c \ - rad-msg.c sck.c shw.c skad.c sys.c sys-ass.c sys-err.c \ - sys-log.c sys-mux.c sys-prv.h sys-tim.c thr.c uch-case.h \ - uch-prop.h tar.c tmr.c utf8.c utl.c utl-mime.c utl-siph.c \ - utl-str.c mar.c mar-cli.c +am__libhio_la_SOURCES_DIST = chr.c dhcp-svr.c dhcp-msg.c dns.c \ + dns-cli.c ecs.c ecs-imp.h err.c fcgi-cli.c fmt.c fmt-imp.h \ + htb.c htrd.c htre.c http.c http-cgi.c http-fcgi.c http-file.c \ + http-prv.h http-prxy.c http-svr.c http-thr.c http-txt.c json.c \ + hio-prv.h hio.c md5.c nwif.c opt.c opt-imp.h path.c pipe.c \ + pro.c pty.c rad-msg.c sck.c shw.c skad.c sys.c sys-ass.c \ + sys-err.c sys-log.c sys-mux.c sys-prv.h sys-tim.c thr.c \ + uch-case.h uch-prop.h tar.c tmr.c utf8.c utl.c utl-mime.c \ + utl-siph.c utl-str.c mar.c mar-cli.c @ENABLE_MARIADB_TRUE@am__objects_1 = libhio_la-mar.lo \ @ENABLE_MARIADB_TRUE@ libhio_la-mar-cli.lo am_libhio_la_OBJECTS = libhio_la-chr.lo libhio_la-dhcp-svr.lo \ - libhio_la-dns.lo libhio_la-dns-cli.lo libhio_la-ecs.lo \ - libhio_la-err.lo libhio_la-fcgi-cli.lo libhio_la-fmt.lo \ - libhio_la-htb.lo libhio_la-htrd.lo libhio_la-htre.lo \ - libhio_la-http.lo libhio_la-http-cgi.lo libhio_la-http-fcgi.lo \ - libhio_la-http-file.lo libhio_la-http-prxy.lo \ - libhio_la-http-svr.lo libhio_la-http-thr.lo \ - libhio_la-http-txt.lo libhio_la-json.lo libhio_la-hio.lo \ - libhio_la-md5.lo libhio_la-nwif.lo libhio_la-opt.lo \ - libhio_la-path.lo libhio_la-pipe.lo libhio_la-pro.lo \ - libhio_la-pty.lo libhio_la-rad-msg.lo libhio_la-sck.lo \ - libhio_la-shw.lo libhio_la-skad.lo libhio_la-sys.lo \ - libhio_la-sys-ass.lo libhio_la-sys-err.lo libhio_la-sys-log.lo \ - libhio_la-sys-mux.lo libhio_la-sys-tim.lo libhio_la-thr.lo \ - libhio_la-tar.lo libhio_la-tmr.lo libhio_la-utf8.lo \ - libhio_la-utl.lo libhio_la-utl-mime.lo libhio_la-utl-siph.lo \ - libhio_la-utl-str.lo $(am__objects_1) + libhio_la-dhcp-msg.lo libhio_la-dns.lo libhio_la-dns-cli.lo \ + libhio_la-ecs.lo libhio_la-err.lo libhio_la-fcgi-cli.lo \ + libhio_la-fmt.lo libhio_la-htb.lo libhio_la-htrd.lo \ + libhio_la-htre.lo libhio_la-http.lo libhio_la-http-cgi.lo \ + libhio_la-http-fcgi.lo libhio_la-http-file.lo \ + libhio_la-http-prxy.lo libhio_la-http-svr.lo \ + libhio_la-http-thr.lo libhio_la-http-txt.lo libhio_la-json.lo \ + libhio_la-hio.lo libhio_la-md5.lo libhio_la-nwif.lo \ + libhio_la-opt.lo libhio_la-path.lo libhio_la-pipe.lo \ + libhio_la-pro.lo libhio_la-pty.lo libhio_la-rad-msg.lo \ + libhio_la-sck.lo libhio_la-shw.lo libhio_la-skad.lo \ + libhio_la-sys.lo libhio_la-sys-ass.lo libhio_la-sys-err.lo \ + libhio_la-sys-log.lo libhio_la-sys-mux.lo libhio_la-sys-tim.lo \ + libhio_la-thr.lo libhio_la-tar.lo libhio_la-tmr.lo \ + libhio_la-utf8.lo libhio_la-utl.lo libhio_la-utl-mime.lo \ + libhio_la-utl-siph.lo libhio_la-utl-str.lo $(am__objects_1) libhio_la_OBJECTS = $(am_libhio_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -199,6 +199,7 @@ DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/ac/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/libhio_la-chr.Plo \ + ./$(DEPDIR)/libhio_la-dhcp-msg.Plo \ ./$(DEPDIR)/libhio_la-dhcp-svr.Plo \ ./$(DEPDIR)/libhio_la-dns-cli.Plo \ ./$(DEPDIR)/libhio_la-dns.Plo ./$(DEPDIR)/libhio_la-ecs.Plo \ @@ -474,15 +475,15 @@ include_HEADERS = hio-chr.h hio-cmn.h hio-dhcp.h hio-dns.h hio-ecs.h \ hio-sck.h hio-shw.h hio-skad.h hio-spl.h hio-str.h hio-tar.h \ hio-thr.h hio-upac.h hio-utl.h hio.h $(am__append_1) lib_LTLIBRARIES = libhio.la -libhio_la_SOURCES = chr.c dhcp-svr.c dns.c dns-cli.c ecs.c ecs-imp.h \ - err.c fcgi-cli.c fmt.c fmt-imp.h htb.c htrd.c htre.c http.c \ - http-cgi.c http-fcgi.c http-file.c http-prv.h http-prxy.c \ - http-svr.c http-thr.c http-txt.c json.c hio-prv.h hio.c md5.c \ - nwif.c opt.c opt-imp.h path.c pipe.c pro.c pty.c rad-msg.c \ - sck.c shw.c skad.c sys.c sys-ass.c sys-err.c sys-log.c \ - sys-mux.c sys-prv.h sys-tim.c thr.c uch-case.h uch-prop.h \ - tar.c tmr.c utf8.c utl.c utl-mime.c utl-siph.c utl-str.c \ - $(am__append_2) +libhio_la_SOURCES = chr.c dhcp-svr.c dhcp-msg.c dns.c dns-cli.c ecs.c \ + ecs-imp.h err.c fcgi-cli.c fmt.c fmt-imp.h htb.c htrd.c htre.c \ + http.c http-cgi.c http-fcgi.c http-file.c http-prv.h \ + http-prxy.c http-svr.c http-thr.c http-txt.c json.c hio-prv.h \ + hio.c md5.c nwif.c opt.c opt-imp.h path.c pipe.c pro.c pty.c \ + rad-msg.c sck.c shw.c skad.c sys.c sys-ass.c sys-err.c \ + sys-log.c sys-mux.c sys-prv.h sys-tim.c thr.c uch-case.h \ + uch-prop.h tar.c tmr.c utf8.c utl.c utl-mime.c utl-siph.c \ + utl-str.c $(am__append_2) libhio_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) libhio_la_CFLAGS = $(CFLAGS_LIB_COMMON) $(am__append_3) libhio_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) $(am__append_4) @@ -583,6 +584,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhio_la-chr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhio_la-dhcp-msg.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhio_la-dhcp-svr.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhio_la-dns-cli.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhio_la-dns.Plo@am__quote@ # am--include-marker @@ -675,6 +677,13 @@ libhio_la-dhcp-svr.lo: dhcp-svr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhio_la_CPPFLAGS) $(CPPFLAGS) $(libhio_la_CFLAGS) $(CFLAGS) -c -o libhio_la-dhcp-svr.lo `test -f 'dhcp-svr.c' || echo '$(srcdir)/'`dhcp-svr.c +libhio_la-dhcp-msg.lo: dhcp-msg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhio_la_CPPFLAGS) $(CPPFLAGS) $(libhio_la_CFLAGS) $(CFLAGS) -MT libhio_la-dhcp-msg.lo -MD -MP -MF $(DEPDIR)/libhio_la-dhcp-msg.Tpo -c -o libhio_la-dhcp-msg.lo `test -f 'dhcp-msg.c' || echo '$(srcdir)/'`dhcp-msg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhio_la-dhcp-msg.Tpo $(DEPDIR)/libhio_la-dhcp-msg.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-msg.c' object='libhio_la-dhcp-msg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhio_la_CPPFLAGS) $(CPPFLAGS) $(libhio_la_CFLAGS) $(CFLAGS) -c -o libhio_la-dhcp-msg.lo `test -f 'dhcp-msg.c' || echo '$(srcdir)/'`dhcp-msg.c + libhio_la-dns.lo: dns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhio_la_CPPFLAGS) $(CPPFLAGS) $(libhio_la_CFLAGS) $(CFLAGS) -MT libhio_la-dns.lo -MD -MP -MF $(DEPDIR)/libhio_la-dns.Tpo -c -o libhio_la-dns.lo `test -f 'dns.c' || echo '$(srcdir)/'`dns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhio_la-dns.Tpo $(DEPDIR)/libhio_la-dns.Plo @@ -1156,6 +1165,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ distclean: distclean-am -rm -f ./$(DEPDIR)/libhio_la-chr.Plo + -rm -f ./$(DEPDIR)/libhio_la-dhcp-msg.Plo -rm -f ./$(DEPDIR)/libhio_la-dhcp-svr.Plo -rm -f ./$(DEPDIR)/libhio_la-dns-cli.Plo -rm -f ./$(DEPDIR)/libhio_la-dns.Plo @@ -1250,6 +1260,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libhio_la-chr.Plo + -rm -f ./$(DEPDIR)/libhio_la-dhcp-msg.Plo -rm -f ./$(DEPDIR)/libhio_la-dhcp-svr.Plo -rm -f ./$(DEPDIR)/libhio_la-dns-cli.Plo -rm -f ./$(DEPDIR)/libhio_la-dns.Plo diff --git a/lib/dhcp-msg.c b/lib/dhcp-msg.c new file mode 100644 index 0000000..4674a54 --- /dev/null +++ b/lib/dhcp-msg.c @@ -0,0 +1,354 @@ +/* + Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "hio-prv.h" + +#include +struct magic_cookie_t +{ + hio_uint32_t value; +}; +typedef struct magic_cookie_t magic_cookie_t; +#include + + +int hio_dhcp4_init_pktbuf (hio_dhcp4_pktbuf_t* pkt, void* buf, hio_oow_t capa) +{ + if (capa < HIO_SIZEOF(*pkt->hdr)) return -1; + pkt->hdr = (hio_dhcp4_pkt_hdr_t*)buf; + pkt->len = HIO_SIZEOF(*pkt->hdr); + pkt->capa = capa; + HIO_MEMSET (pkt->hdr, 0, HIO_SIZEOF(*pkt->hdr)); + return 0; +} + +int hio_dhcp4_add_option (hio_dhcp4_pktbuf_t* pkt, int code, void* optr, hio_uint8_t olen) +{ + hio_dhcp4_opt_hdr_t* opthdr; + magic_cookie_t* cookie; + int optlen; + +/* TODO: support to override sname and file */ + if (pkt->len < HIO_SIZEOF(*pkt->hdr) || pkt->capa < pkt->len) + { + /* the pktbuf_t structure got messy */ + return -1; + } + + if (pkt->len == HIO_SIZEOF(*pkt->hdr)) + { + /* the first option is being added */ + if (pkt->capa - pkt->len < HIO_SIZEOF(*cookie)) return -1; + cookie = (magic_cookie_t*)((hio_uint8_t*)pkt->hdr + pkt->len); + cookie->value = HIO_CONST_HTON32(HIO_DHCP4_MAGIC_COOKIE); + pkt->len += HIO_SIZEOF(*cookie); + } + else if (pkt->len < HIO_SIZEOF(*pkt->hdr) + HIO_SIZEOF(*cookie)) + { + /* no space for cookie */ + return -1; + } + else + { + cookie = (magic_cookie_t*)(pkt->hdr + 1); + if (cookie->value != HIO_CONST_HTON32(HIO_DHCP4_MAGIC_COOKIE)) return -1; + } + +/* do i need to disallow adding a new option if END is found? */ + + if (code == HIO_DHCP4_OPT_PADDING || code == HIO_DHCP4_OPT_END) + { + optlen = 1; /* no length field in the header and no option palyload */ + if (pkt->capa - pkt->len < optlen) return -1; + opthdr = (hio_dhcp4_opt_hdr_t*)((hio_uint8_t*)pkt->hdr + pkt->len); + } + else + { + optlen = HIO_SIZEOF(*opthdr) + olen; + + if (pkt->capa - pkt->len < optlen) return -1; + opthdr = (hio_dhcp4_opt_hdr_t*)((hio_uint8_t*)pkt->hdr + pkt->len); + + opthdr->len = olen; + if (olen > 0) HIO_MEMCPY (opthdr + 1, optr, olen); + } + + opthdr->code = code; + pkt->len += optlen; + + return 0; +} + +int hio_dhcp4_delete_option (hio_dhcp4_pktbuf_t* pkt, int code) +{ + hio_dhcp4_opt_hdr_t* ohdr; + hio_oow_t olen; + hio_uint8_t* ovend; + + ohdr = hio_dhcp4_find_option((hio_dhcp4_pktinf_t*)pkt, code); + if (!ohdr) return -1; + + olen = (code == HIO_DHCP4_OPT_PADDING || code == HIO_DHCP4_OPT_END)? 1: (ohdr->len) + HIO_SIZEOF(*ohdr); + + if ((ohdr >= pkt->hdr->file && ohdr < (ovend = (hio_uint8_t*)pkt->hdr->file + HIO_SIZEOF(pkt->hdr->file))) || + (ohdr >= pkt->hdr->sname && ohdr < (ovend = (hio_uint8_t*)pkt->hdr->sname + HIO_SIZEOF(pkt->hdr->sname)))) + { + /* the option resides in the overload area */ + HIO_MEMMOVE (ohdr, (hio_uint8_t*)ohdr + olen, ovend - ((hio_uint8_t*)ohdr + olen)); + HIO_MEMSET (ovend - olen, 0, olen); + /* packet length remains unchanged */ + } + else + { + HIO_MEMMOVE (ohdr, (hio_uint8_t*)ohdr + olen, ((hio_uint8_t*)pkt->hdr + pkt->len) - ((hio_uint8_t*)ohdr + olen)); + pkt->len -= olen; + } + return 0; +} + +void hio_dhcp4_compact_options (hio_dhcp4_pktbuf_t* pkt) +{ + /* TODO: move some optiosn to sname or file fields if they are not in use. */ +} + +static hio_uint8_t* get_option_start (const hio_dhcp4_pkt_hdr_t* pkt, hio_oow_t len, hio_oow_t* olen) +{ + magic_cookie_t* cookie; + hio_oow_t optlen; + + /* check if a packet is large enough to hold the known header */ + if (len < HIO_SIZEOF(hio_dhcp4_pkt_hdr_t)) return HIO_NULL; + + /* get the length of option fields */ + optlen = len - HIO_SIZEOF(hio_dhcp4_pkt_hdr_t); + + /* check if a packet is large enough to have a magic cookie */ + if (optlen < HIO_SIZEOF(*cookie)) return HIO_NULL; + + /* get the pointer to the beginning of options */ + cookie = (magic_cookie_t*)(pkt + 1); + + /* check if the packet contains the right magic cookie */ + if (cookie->value != HIO_CONST_HTON32(HIO_DHCP4_MAGIC_COOKIE)) return HIO_NULL; + + *olen = optlen - HIO_SIZEOF(*cookie); + return (hio_uint8_t*)(cookie + 1); +} + +int hio_dhcp4_walk_options (const hio_dhcp4_pktinf_t* pkt, hio_dhcp4_opt_walker_t walker) +{ + const hio_uint8_t* optptr[3]; + hio_oow_t optlen[3]; + int i; + + optptr[0] = get_option_start(pkt->hdr, pkt->len, &optlen[0]); + if (optptr[0] == HIO_NULL) return -1; + + optptr[1] = (const hio_uint8_t*)pkt->hdr->file; + optptr[2] = (const hio_uint8_t*)pkt->hdr->sname; + optlen[1] = 0; + optlen[2] = 0; + + for (i = 0; i < 3; i++) + { + const hio_uint8_t* opt = optptr[i]; + const hio_uint8_t* end = opt + optlen[i]; + + while (opt < end) + { + /* option code */ + hio_dhcp4_opt_hdr_t* opthdr; + + if (opt + HIO_SIZEOF(*opthdr) >= end) return -1; + opthdr = (hio_dhcp4_opt_hdr_t*)opt; + opt += HIO_SIZEOF(*opthdr); + + /* no len field exists for PADDING and END */ + if (opthdr->code == HIO_DHCP4_OPT_PADDING) continue; + if (opthdr->code == HIO_DHCP4_OPT_END) break; + + if (opt + opthdr->len >= end) return -1; /* the length field is wrong */ + + if (opthdr->code == HIO_DHCP4_OPT_OVERLOAD) + { + if (opthdr->len != 1) return -1; + if (*opt & HIO_DHCP4_OPT_OVERLOAD_FILE) optlen[1] = HIO_SIZEOF(pkt->hdr->file); + if (*opt & HIO_DHCP4_OPT_OVERLOAD_SNAME) optlen[2] = HIO_SIZEOF(pkt->hdr->sname); + } + else + { + int n; + if ((n = walker(opthdr)) <= -1) return -1; + if (n == 0) break; /* stop */ + } + + opt += opthdr->len; + } + } + + return 0; +} + +hio_dhcp4_opt_hdr_t* hio_dhcp4_find_option (const hio_dhcp4_pktinf_t* pkt, int code) +{ + const hio_uint8_t* optptr[3]; + hio_oow_t optlen[3]; + int i; + + optptr[0] = get_option_start(pkt->hdr, pkt->len, &optlen[0]); + if (!optptr[0]) return HIO_NULL; + + optptr[1] = (const hio_uint8_t*)pkt->hdr->file; + optptr[2] = (const hio_uint8_t*)pkt->hdr->sname; + optlen[1] = 0; + optlen[2] = 0; + + for (i = 0; i < 3; i++) + { + const hio_uint8_t* opt = optptr[i]; + const hio_uint8_t* end = opt + optlen[i]; + + while (opt < end) + { + /* option code */ + hio_dhcp4_opt_hdr_t* opthdr; + + /* at least 1 byte is available. the check is because of PADDING or END */ + if (*opt == HIO_DHCP4_OPT_PADDING) + { + opt++; + continue; + } + if (*opt == HIO_DHCP4_OPT_END) + { + if (code == HIO_DHCP4_OPT_END) + { + /* the caller must handle END specially becuase it is only 1 byte long + * for no length part in the header */ + return (hio_dhcp4_opt_hdr_t*)opt; + } + break; + } + + if (opt + HIO_SIZEOF(*opthdr) > end) break; + + opthdr = (hio_dhcp4_opt_hdr_t*)opt; + opt += HIO_SIZEOF(*opthdr); + + /* option length */ + + if (opthdr->code == code) + { + if (opt + opthdr->len > end) break; + return opthdr; + } + + /* + * If option overload is used, the SName and/or File fields are read and + * interpreted in the same way as the Options field, after all options in + * the Option field are parsed. If the message actually does need to carry + * a server name or boot file, these are included as separate options + * (number 66 and number 67, respectively), which are variable-length and + * can therefore be made exactly the length needed. + */ + if (opthdr->code == HIO_DHCP4_OPT_OVERLOAD) + { + if (opthdr->len != 1) break; + if (*opt & HIO_DHCP4_OPT_OVERLOAD_FILE) optlen[1] = HIO_SIZEOF(pkt->hdr->file); + if (*opt & HIO_DHCP4_OPT_OVERLOAD_SNAME) optlen[2] = HIO_SIZEOF(pkt->hdr->sname); + } + + opt += opthdr->len; + } + } + + return HIO_NULL; +} + +hio_uint8_t* hio_dhcp4_get_relay_suboption (const hio_uint8_t* ptr, hio_uint8_t len, int code, hio_uint8_t* olen) +{ + const hio_uint8_t* end = ptr + len; + + while (ptr < end) + { + hio_uint8_t oc, ol; + + oc = *ptr++; + + if (ptr >= end) break; + ol = *ptr++; + + if (oc == code) + { + *olen = ol; + return (hio_uint8_t*)ptr; + } + + ptr += ol; + } + + return HIO_NULL; +} + + +/* -------------------------------------------------------------------------- */ + +hio_dhcp6_opt_hdr_t* hio_dhcp6_find_option (const hio_dhcp6_pktinf_t* pkt, int code) +{ + hio_dhcp6_opt_hdr_t* opt; + hio_oow_t rem, opt_len; + + if (pkt->len < HIO_SIZEOF(hio_dhcp6_pkt_hdr_t)) return HIO_NULL; + + if (pkt->hdr->msgtype == HIO_DHCP6_MSG_RELAYFORW || pkt->hdr->msgtype == HIO_DHCP6_MSG_RELAYREPL) + { + if (pkt->len < HIO_SIZEOF(hio_dhcp6_relay_hdr_t)) return HIO_NULL; + + rem = pkt->len - HIO_SIZEOF(hio_dhcp6_relay_hdr_t); + opt = (hio_dhcp6_opt_hdr_t*)(((hio_dhcp6_relay_hdr_t*)pkt->hdr) + 1); + } + else + { + rem = pkt->len - HIO_SIZEOF(hio_dhcp6_pkt_hdr_t); + opt = (hio_dhcp6_opt_hdr_t*)(pkt->hdr + 1); + } + + while (rem >= HIO_SIZEOF(hio_dhcp6_opt_hdr_t)) + { + if (hio_ntoh16(opt->code) == code) + { + if (rem - HIO_SIZEOF(hio_dhcp6_opt_hdr_t) < hio_ntoh16(opt->len)) return HIO_NULL; /* probably the packet is ill-formed */ + return opt; + } + + opt_len = HIO_SIZEOF(hio_dhcp6_opt_hdr_t) + hio_ntoh16(opt->len); + if (rem < opt_len) break; + rem -= opt_len; + opt = (hio_dhcp6_opt_hdr_t*)((hio_uint8_t*)(opt + 1) + hio_ntoh16(opt->len)); + + } + + return HIO_NULL; +} diff --git a/lib/hio-dhcp.h b/lib/hio-dhcp.h index 71b0437..0096007 100644 --- a/lib/hio-dhcp.h +++ b/lib/hio-dhcp.h @@ -28,6 +28,167 @@ #include #include +/* ---------------------------------------------------------------- */ + +#define HIO_DHCP4_SERVER_PORT (67) +#define HIO_DHCP4_CLIENT_PORT (68) +#define HIO_DHCP4_MAGIC_COOKIE (0x63825363) + +/* operation code */ +enum hio_dhcp4_op_t +{ + HIO_DHCP4_OP_BOOTREQUEST = 1, + HIO_DHCP4_OP_BOOTREPLY = 2 +}; + +enum hio_dhcp4_htype_t +{ + HIO_DHCP4_HTYPE_ETHERNET = 1, + HIO_DHCP4_HTYPE_IEEE802 = 6, + HIO_DHCP4_HTYPE_ARCNET = 7, + HIO_DHCP4_HTYPE_APPLETALK = 8, + HIO_DHCP4_HTYPE_HDLC = 17, + HIO_DHCP4_HTYPE_ATM = 19, + HIO_DHCP4_HTYPE_INFINIBAND = 32 +}; + +/* option codes (partial) */ +enum hio_dhcp4_opt_t +{ + HIO_DHCP4_OPT_PADDING = 0x00, + HIO_DHCP4_OPT_SUBNET = 0x01, + HIO_DHCP4_OPT_TIME_OFFSET = 0x02, + HIO_DHCP4_OPT_ROUTER = 0x03, + HIO_DHCP4_OPT_TIME_SERVER = 0x04, + HIO_DHCP4_OPT_NAME_SERVER = 0x05, + HIO_DHCP4_OPT_DNS_SERVER = 0x06, + HIO_DHCP4_OPT_LOG_SERVER = 0x07, + HIO_DHCP4_OPT_COOKIE_SERVER = 0x08, + HIO_DHCP4_OPT_LPR_SERVER = 0x09, + HIO_DHCP4_OPT_HOST_NAME = 0x0c, + HIO_DHCP4_OPT_BOOT_SIZE = 0x0d, + HIO_DHCP4_OPT_DOMAIN_NAME = 0x0f, + HIO_DHCP4_OPT_SWAP_SERVER = 0x10, + HIO_DHCP4_OPT_ROOT_PATH = 0x11, + HIO_DHCP4_OPT_IP_TTL = 0x17, + HIO_DHCP4_OPT_MTU = 0x1a, + HIO_DHCP4_OPT_BROADCAST = 0x1c, + HIO_DHCP4_OPT_NTP_SERVER = 0x2a, + HIO_DHCP4_OPT_WINS_SERVER = 0x2c, + HIO_DHCP4_OPT_REQUESTED_IPADDR = 0x32, + HIO_DHCP4_OPT_LEASE_TIME = 0x33, + HIO_DHCP4_OPT_OVERLOAD = 0x34, /* overload sname or file */ + HIO_DHCP4_OPT_MESSAGE_TYPE = 0x35, + HIO_DHCP4_OPT_SERVER_ID = 0x36, + HIO_DHCP4_OPT_PARAM_REQ = 0x37, + HIO_DHCP4_OPT_MESSAGE = 0x38, + HIO_DHCP4_OPT_MAX_SIZE = 0x39, + HIO_DHCP4_OPT_T1 = 0x3a, + HIO_DHCP4_OPT_T2 = 0x3b, + HIO_DHCP4_OPT_VENDOR = 0x3c, + HIO_DHCP4_OPT_CLIENT_ID = 0x3d, + HIO_DHCP4_OPT_RELAY = 0x52, + HIO_DHCP4_OPT_SUBNET_SELECTION = 0x76, + HIO_DHCP4_OPT_END = 0xFF +}; + +/* flags for HIO_DHCP4_OPT_OVERLOAD */ +enum hio_dhcp4_opt_overload_t +{ + HIO_DHCP4_OPT_OVERLOAD_FILE = (1 << 0), + HIO_DHCP4_OPT_OVERLOAD_SNAME = (1 << 1) +}; + +/* flags for HIO_DHCP4_OPT_OVERLOAD */ +enum hio_dhcp4_opt_relay_t +{ + HIO_DHCP4_OPT_RELAY_CIRCUIT_ID = 1, + HIO_DHCP4_OPT_RELAY_REMOTE_ID = 2 +}; + +/* message type */ +enum hio_dhcp4_msg_t +{ + HIO_DHCP4_MSG_DISCOVER = 1, + HIO_DHCP4_MSG_OFFER = 2, + HIO_DHCP4_MSG_REQUEST = 3, + HIO_DHCP4_MSG_DECLINE = 4, + HIO_DHCP4_MSG_ACK = 5, + HIO_DHCP4_MSG_NAK = 6, + HIO_DHCP4_MSG_RELEASE = 7, + HIO_DHCP4_MSG_INFORM = 8, + + /*HIO_DHCP4_MSG_RENEW = 9,*/ + + HIO_DHCP4_MSG_LEASE_QUERY = 10, + HIO_DHCP4_MSG_LEASE_UNASSIGNED = 11, + HIO_DHCP4_MSG_LEASE_UNKNOWN = 12, + HIO_DHCP4_MSG_LEASE_ACTIVE = 13, + + HIO_DHCP4_MSG_BULK_LEASE_QUERY = 14, + HIO_DHCP4_MSG_LEASE_QUERY_DONE = 15 +}; + +/* --------------------------------------------------- */ +#include +/* --------------------------------------------------- */ + +struct hio_dhcp4_pkt_hdr_t +{ + hio_uint8_t op; + hio_uint8_t htype; + hio_uint8_t hlen; + hio_uint8_t hops; + hio_uint32_t xid; /* transaction id */ + hio_uint16_t secs; /* seconds elapsed */ + hio_uint16_t flags; /* bootp flags */ + hio_uint32_t ciaddr; /* client ip */ + hio_uint32_t yiaddr; /* your ip */ + hio_uint32_t siaddr; /* next server ip */ + hio_uint32_t giaddr; /* relay agent ip */ + hio_uint8_t chaddr[16]; /* client mac */ + + char sname[64]; /* server host name */ + char file[128]; /* boot file name */ + + /* options are placed after the header. + * the first four bytes of the options compose a magic cookie + * 0x63 0x82 0x53 0x63 */ +}; +typedef struct hio_dhcp4_pkt_hdr_t hio_dhcp4_pkt_hdr_t; + +struct hio_dhcp4_opt_hdr_t +{ + hio_uint8_t code; + hio_uint8_t len; +}; +typedef struct hio_dhcp4_opt_hdr_t hio_dhcp4_opt_hdr_t; + +/* --------------------------------------------------- */ +#include +/* --------------------------------------------------- */ + + +typedef int (*hio_dhcp4_opt_walker_t) (hio_dhcp4_opt_hdr_t* opt); + +struct hio_dhcp4_pktinf_t +{ + hio_dhcp4_pkt_hdr_t* hdr; + hio_oow_t len; +}; +typedef struct hio_dhcp4_pktinf_t hio_dhcp4_pktinf_t; + +struct hio_dhcp4_pktbuf_t +{ + hio_dhcp4_pkt_hdr_t* hdr; + hio_oow_t len; + hio_oow_t capa; +}; +typedef struct hio_dhcp4_pktbuf_t hio_dhcp4_pktbuf_t; + + +/* ---------------------------------------------------------------- */ + #define HIO_DHCP6_SERVER_PORT (547) #define HIO_DHCP6_CLIENT_PORT (546) #define HIO_DHCP6_HOP_COUNT_LIMIT (32) @@ -52,15 +213,26 @@ typedef enum hio_dhcp6_msg_t hio_dhcp6_msg_t; enum hio_dhcp6_opt_t { + HIO_DHCP6_OPT_CLIENTID = 1, + HIO_DHCP6_OPT_SERVERID = 2, + HIO_DHCP6_OPT_IA_NA = 3, + HIO_DHCP6_OPT_IA_TA = 4, + HIO_DHCP6_OPT_IAADDR = 5, + HIO_DHCP6_OPT_PREFERENCE = 7, + HIO_DHCP6_OPT_ELAPSED_TIME = 8, HIO_DHCP6_OPT_RELAY_MESSAGE = 9, - HIO_DHCP6_OPT_INTERFACE_ID = 18 + HIO_DHCP6_OPT_RAPID_COMMIT = 14, + HIO_DHCP6_OPT_USER_CLASS = 15, + HIO_DHCP6_OPT_VENDOR_CLASS = 16, + HIO_DHCP6_OPT_INTERFACE_ID = 18, + HIO_DHCP6_OPT_IA_PD = 25, + HIO_DHCP6_OPT_IAPREFIX = 26 }; typedef enum hio_dhcp6_opt_t hio_dhcp6_opt_t; - - -/* ---------------------------------------------------------------- */ +/* --------------------------------------------------- */ #include +/* --------------------------------------------------- */ struct hio_dhcp6_pkt_hdr_t { @@ -85,8 +257,9 @@ struct hio_dhcp6_opt_hdr_t }; typedef struct hio_dhcp6_opt_hdr_t hio_dhcp6_opt_hdr_t; +/* --------------------------------------------------- */ #include - +/* --------------------------------------------------- */ struct hio_dhcp6_pktinf_t { @@ -95,6 +268,7 @@ struct hio_dhcp6_pktinf_t }; typedef struct hio_dhcp6_pktinf_t hio_dhcp6_pktinf_t; + /* ---------------------------------------------------------------- */ typedef struct hio_svc_dhcs_t hio_svc_dhcs_t; @@ -105,6 +279,66 @@ typedef struct hio_svc_dhcs_t hio_svc_dhcs_t; extern "C" { #endif +HIO_EXPORT int hio_dhcp4_init_pktbuf ( + hio_dhcp4_pktbuf_t* pkt, + void* buf, + hio_oow_t capa +); + +HIO_EXPORT int hio_dhcp4_add_option ( + hio_dhcp4_pktbuf_t* pkt, + int code, + void* optr, /**< option data pointer */ + hio_uint8_t olen /**< option data length */ +); + +HIO_EXPORT int hio_dhcp4_delete_option ( + hio_dhcp4_pktbuf_t* pkt, + int code +); + +HIO_EXPORT void hio_dhcp4_compact_options ( + hio_dhcp4_pktbuf_t* pkt +); + +#if 0 +HIO_EXPORT int hio_dhcp4_add_options ( + hio_dhcp4_pkt_hdr_t* pkt, + hio_oow_t len, + hio_oow_t max, + int code, + hio_uint8_t* optr, /* option data */ + hio_uint8_t olen /* option length */ +); +#endif + +HIO_EXPORT int hio_dhcp4_walk_options ( + const hio_dhcp4_pktinf_t* pkt, + hio_dhcp4_opt_walker_t walker +); + +HIO_EXPORT hio_dhcp4_opt_hdr_t* hio_dhcp4_find_option ( + const hio_dhcp4_pktinf_t* pkt, + int code +); + +HIO_EXPORT hio_uint8_t* hio_dhcp4_get_relay_suboption ( + const hio_uint8_t* ptr, + hio_uint8_t len, + int code, + hio_uint8_t* olen +); + +/* ---------------------------------------------------------------- */ + +HIO_EXPORT hio_dhcp6_opt_hdr_t* hio_dhcp6_find_option ( + const hio_dhcp6_pktinf_t* pkt, + int code +); + +/* ---------------------------------------------------------------- */ + + HIO_EXPORT hio_svc_dhcs_t* hio_svc_dhcs_start ( hio_t* hio, const hio_skad_t* local_binds, @@ -118,8 +352,7 @@ HIO_EXPORT void hio_svc_dhcs_stop ( #if defined(HIO_HAVE_INLINE) static HIO_INLINE hio_t* hio_svc_dhcs_gethio(hio_svc_dhcs_t* svc) { return hio_svc_gethio((hio_svc_t*)svc); } #else -# define hio_svc_dhcs_gethio(svc) hio_svc_gethio(svc) - +#define hio_svc_dhcs_gethio(svc) hio_svc_gethio(svc) #endif