diff options
Diffstat (limited to 'libdnet-stripped/src')
40 files changed, 8973 insertions, 0 deletions
diff --git a/libdnet-stripped/src/Makefile.am b/libdnet-stripped/src/Makefile.am new file mode 100644 index 0000000..2f14d98 --- /dev/null +++ b/libdnet-stripped/src/Makefile.am @@ -0,0 +1,11 @@ +## $Id: Makefile.am 625 2006-01-19 06:11:01Z dugsong $ + +include $(top_srcdir)/Makefile.am.common + +lib_LTLIBRARIES = libdnet.la + +libdnet_la_SOURCES = addr-util.c addr.c blob.c ip-util.c ip6.c rand.c + +libdnet_la_LIBADD = @LTLIBOBJS@ + +libdnet_la_LDFLAGS = -version-info 1:1:0 diff --git a/libdnet-stripped/src/Makefile.in b/libdnet-stripped/src/Makefile.in new file mode 100644 index 0000000..16880e3 --- /dev/null +++ b/libdnet-stripped/src/Makefile.in @@ -0,0 +1,470 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/Makefile.am.common arp-bsd.c arp-ioctl.c \ + arp-none.c arp-win32.c err.c eth-bsd.c eth-dlpi.c eth-linux.c \ + eth-ndd.c eth-none.c eth-pfilt.c eth-snoop.c eth-win32.c \ + fw-none.c intf-win32.c intf.c ip-cooked.c ip-win32.c ip.c \ + memcmp.c route-bsd.c route-hpux.c route-linux.c route-none.c \ + route-win32.c strlcpy.c strsep.c tun-bsd.c \ + tun-linux.c tun-none.c tun-solaris.c +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libdnet_la_DEPENDENCIES = @LTLIBOBJS@ +am_libdnet_la_OBJECTS = addr-util.lo addr.lo blob.lo ip-util.lo ip6.lo \ + rand.lo +libdnet_la_OBJECTS = $(am_libdnet_la_OBJECTS) +libdnet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libdnet_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libdnet_la_SOURCES) +DIST_SOURCES = $(libdnet_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECKINC = @CHECKINC@ +CHECKLIB = @CHECKLIB@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON = @PYTHON@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCLINC = @TCLINC@ +TCLLIB = @TCLLIB@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign no-dependencies +AM_CPPFLAGS = -I$(top_srcdir)/include +lib_LTLIBRARIES = libdnet.la +libdnet_la_SOURCES = addr-util.c addr.c blob.c ip-util.c ip6.c rand.c +libdnet_la_LIBADD = @LTLIBOBJS@ +libdnet_la_LDFLAGS = -version-info 1:1:0 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.am.common $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdnet.la: $(libdnet_la_OBJECTS) $(libdnet_la_DEPENDENCIES) + $(libdnet_la_LINK) -rpath $(libdir) $(libdnet_la_OBJECTS) $(libdnet_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libdnet-stripped/src/addr-util.c b/libdnet-stripped/src/addr-util.c new file mode 100644 index 0000000..09c0807 --- /dev/null +++ b/libdnet-stripped/src/addr-util.c @@ -0,0 +1,304 @@ +/* + * addr-util.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: addr-util.c 539 2005-01-23 07:36:54Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +static const char *octet2dec[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", + "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", + "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", + "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", + "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", + "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", + "119", "120", "121", "122", "123", "124", "125", "126", "127", + "128", "129", "130", "131", "132", "133", "134", "135", "136", + "137", "138", "139", "140", "141", "142", "143", "144", "145", + "146", "147", "148", "149", "150", "151", "152", "153", "154", + "155", "156", "157", "158", "159", "160", "161", "162", "163", + "164", "165", "166", "167", "168", "169", "170", "171", "172", + "173", "174", "175", "176", "177", "178", "179", "180", "181", + "182", "183", "184", "185", "186", "187", "188", "189", "190", + "191", "192", "193", "194", "195", "196", "197", "198", "199", + "200", "201", "202", "203", "204", "205", "206", "207", "208", + "209", "210", "211", "212", "213", "214", "215", "216", "217", + "218", "219", "220", "221", "222", "223", "224", "225", "226", + "227", "228", "229", "230", "231", "232", "233", "234", "235", + "236", "237", "238", "239", "240", "241", "242", "243", "244", + "245", "246", "247", "248", "249", "250", "251", "252", "253", + "254", "255" +}; + +static const char *octet2hex[] = { + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", + "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", + "2c", "2d", "2e", "2f", "30", "31", "32", "33", "34", "35", "36", + "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", "40", "41", + "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", + "4d", "4e", "4f", "50", "51", "52", "53", "54", "55", "56", "57", + "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", + "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", + "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", "78", + "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83", + "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", + "8f", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", + "9a", "9b", "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", + "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", + "bb", "bc", "bd", "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", + "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", + "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", + "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5", "e6", + "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", "f0", "f1", + "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", + "fd", "fe", "ff" +}; + +char * +eth_ntop(const eth_addr_t *eth, char *dst, size_t len) +{ + const char *x; + char *p = dst; + int i; + + if (len < 18) + return (NULL); + + for (i = 0; i < ETH_ADDR_LEN; i++) { + for (x = octet2hex[eth->data[i]]; (*p = *x) != '\0'; x++, p++) + ; + *p++ = ':'; + } + p[-1] = '\0'; + + return (dst); +} + +char * +eth_ntoa(const eth_addr_t *eth) +{ + struct addr a; + + addr_pack(&a, ADDR_TYPE_ETH, ETH_ADDR_BITS, eth->data, ETH_ADDR_LEN); + return (addr_ntoa(&a)); +} + +int +eth_pton(const char *p, eth_addr_t *eth) +{ + char *ep; + long l; + int i; + + for (i = 0; i < ETH_ADDR_LEN; i++) { + l = strtol(p, &ep, 16); + if (ep == p || l < 0 || l > 0xff || + (i < ETH_ADDR_LEN - 1 && *ep != ':')) + break; + eth->data[i] = (u_char)l; + p = ep + 1; + } + return ((i == ETH_ADDR_LEN && *ep == '\0') ? 0 : -1); +} + +char * +ip_ntop(const ip_addr_t *ip, char *dst, size_t len) +{ + const char *d; + char *p = dst; + u_char *data = (u_char *)ip; + int i; + + if (len < 16) + return (NULL); + + for (i = 0; i < IP_ADDR_LEN; i++) { + for (d = octet2dec[data[i]]; (*p = *d) != '\0'; d++, p++) + ; + *p++ = '.'; + } + p[-1] = '\0'; + + return (dst); +} + +char * +ip_ntoa(const ip_addr_t *ip) +{ + struct addr a; + + addr_pack(&a, ADDR_TYPE_IP, IP_ADDR_BITS, ip, IP_ADDR_LEN); + return (addr_ntoa(&a)); +} + +int +ip_pton(const char *p, ip_addr_t *ip) +{ + u_char *data = (u_char *)ip; + char *ep; + long l; + int i; + + for (i = 0; i < IP_ADDR_LEN; i++) { + l = strtol(p, &ep, 10); + if (ep == p || l < 0 || l > 0xff || + (i < IP_ADDR_LEN - 1 && *ep != '.')) + break; + data[i] = (u_char)l; + p = ep + 1; + } + return ((i == IP_ADDR_LEN && *ep == '\0') ? 0 : -1); +} + +char * +ip6_ntop(const ip6_addr_t *ip6, char *dst, size_t len) +{ + uint16_t data[IP6_ADDR_LEN / 2]; + struct { int base, len; } best, cur; + char *p = dst; + int i; + + cur.len = best.len = 0; + + if (len < 46) + return (NULL); + + /* Copy into 16-bit array. */ + for (i = 0; i < IP6_ADDR_LEN / 2; i++) { + data[i] = ip6->data[2 * i] << 8; + data[i] |= ip6->data[2 * i + 1]; + } + + best.base = cur.base = -1; + /* + * Algorithm borrowed from Vixie's inet_pton6() + */ + for (i = 0; i < IP6_ADDR_LEN; i += 2) { + if (data[i / 2] == 0) { + if (cur.base == -1) { + cur.base = i; + cur.len = 0; + } else + cur.len += 2; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1 && (best.base == -1 || cur.len > best.len)) + best = cur; + if (best.base != -1 && best.len < 2) + best.base = -1; + if (best.base == 0) + *p++ = ':'; + + for (i = 0; i < IP6_ADDR_LEN; i += 2) { + if (i == best.base) { + *p++ = ':'; + i += best.len; + } else if (i == 12 && best.base == 0 && + (best.len == 10 || (best.len == 8 && + data[5] == 0xffff))) { + if (ip_ntop((ip_addr_t *)&data[6], p, + len - (p - dst)) == NULL) + return (NULL); + return (dst); + } else p += sprintf(p, "%x:", data[i / 2]); + } + if (best.base + 2 + best.len == IP6_ADDR_LEN) { + *p = '\0'; + } else + p[-1] = '\0'; + + return (dst); +} + +char * +ip6_ntoa(const ip6_addr_t *ip6) +{ + struct addr a; + + addr_pack(&a, ADDR_TYPE_IP6, IP6_ADDR_BITS, ip6->data, IP6_ADDR_LEN); + return (addr_ntoa(&a)); +} + +int +ip6_pton(const char *p, ip6_addr_t *ip6) +{ + uint16_t data[8], *u = (uint16_t *)ip6->data; + int i, j, n, z = -1; + char *ep; + long l; + + if (*p == ':') + p++; + + for (n = 0; n < 8; n++) { + l = strtol(p, &ep, 16); + + if (ep == p) { + if (ep[0] == ':' && z == -1) { + z = n; + p++; + } else if (ep[0] == '\0') { + break; + } else { + return (-1); + } + } else if (ep[0] == '.' && n <= 6) { + if (ip_pton(p, (ip_addr_t *)(data + n)) < 0) + return (-1); + n += 2; + ep = ""; /* XXX */ + break; + } else if (l >= 0 && l <= 0xffff) { + data[n] = htons((uint16_t)l); + + if (ep[0] == '\0') { + n++; + break; + } else if (ep[0] != ':' || ep[1] == '\0') + return (-1); + + p = ep + 1; + } else + return (-1); + } + if (n == 0 || *ep != '\0' || (z == -1 && n != 8)) + return (-1); + + for (i = 0; i < z; i++) { + u[i] = data[i]; + } + while (i < 8 - (n - z - 1)) { + u[i++] = 0; + } + for (j = z + 1; i < 8; i++, j++) { + u[i] = data[j]; + } + return (0); +} diff --git a/libdnet-stripped/src/addr.c b/libdnet-stripped/src/addr.c new file mode 100644 index 0000000..7008966 --- /dev/null +++ b/libdnet-stripped/src/addr.c @@ -0,0 +1,494 @@ +/* + * addr.c + * + * Network address operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: addr.c 610 2005-06-26 18:23:26Z dugsong $ + */ + +#ifdef WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <sys/types.h> +#ifdef HAVE_NET_IF_H +# include <sys/socket.h> +# include <net/if.h> +#endif +#ifdef HAVE_NET_IF_DL_H +# include <net/if_dl.h> +#endif +#ifdef HAVE_NET_RAW_H +# include <net/raw.h> +#endif + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +union sockunion { +#ifdef HAVE_NET_IF_DL_H + struct sockaddr_dl sdl; +#endif + struct sockaddr_in sin; +#ifdef HAVE_SOCKADDR_IN6 + struct sockaddr_in6 sin6; +#endif + struct sockaddr sa; +#ifdef AF_RAW + struct sockaddr_raw sr; +#endif +}; + +int +addr_cmp(const struct addr *a, const struct addr *b) +{ + int i, j, k; + + /* XXX */ + if ((i = a->addr_type - b->addr_type) != 0) + return (i); + + /* XXX - 10.0.0.1 is "smaller" than 10.0.0.0/8? */ + if ((i = a->addr_bits - b->addr_bits) != 0) + return (i); + + j = b->addr_bits / 8; + + for (i = 0; i < j; i++) { + if ((k = a->addr_data8[i] - b->addr_data8[i]) != 0) + return (k); + } + if ((k = b->addr_bits % 8) == 0) + return (0); + + k = (~(unsigned int)0) << (8 - k); + i = b->addr_data8[j] & k; + j = a->addr_data8[j] & k; + + return (j - i); +} + +int +addr_net(const struct addr *a, struct addr *b) +{ + uint32_t mask; + int i, j; + + if (a->addr_type == ADDR_TYPE_IP) { + addr_btom(a->addr_bits, &mask, IP_ADDR_LEN); + b->addr_type = ADDR_TYPE_IP; + b->addr_bits = IP_ADDR_BITS; + b->addr_ip = a->addr_ip & mask; + } else if (a->addr_type == ADDR_TYPE_ETH) { + memcpy(b, a, sizeof(*b)); + if (a->addr_data8[0] & 0x1) + memset(b->addr_data8 + 3, 0, 3); + b->addr_bits = ETH_ADDR_BITS; + } else if (a->addr_type == ADDR_TYPE_IP6) { + if (a->addr_bits > IP6_ADDR_BITS) + return (-1); + b->addr_type = ADDR_TYPE_IP6; + b->addr_bits = IP6_ADDR_BITS; + memset(&b->addr_ip6, 0, IP6_ADDR_LEN); + + switch ((i = a->addr_bits / 32)) { + case 4: b->addr_data32[3] = a->addr_data32[3]; + case 3: b->addr_data32[2] = a->addr_data32[2]; + case 2: b->addr_data32[1] = a->addr_data32[1]; + case 1: b->addr_data32[0] = a->addr_data32[0]; + } + if ((j = a->addr_bits % 32) > 0) { + addr_btom(j, &mask, sizeof(mask)); + b->addr_data32[i] = a->addr_data32[i] & mask; + } + } else + return (-1); + + return (0); +} + +int +addr_bcast(const struct addr *a, struct addr *b) +{ + struct addr mask; + + if (a->addr_type == ADDR_TYPE_IP) { + addr_btom(a->addr_bits, &mask.addr_ip, IP_ADDR_LEN); + b->addr_type = ADDR_TYPE_IP; + b->addr_bits = IP_ADDR_BITS; + b->addr_ip = (a->addr_ip & mask.addr_ip) | + (~0L & ~mask.addr_ip); + } else if (a->addr_type == ADDR_TYPE_ETH) { + b->addr_type = ADDR_TYPE_ETH; + b->addr_bits = ETH_ADDR_BITS; + memcpy(&b->addr_eth, ETH_ADDR_BROADCAST, ETH_ADDR_LEN); + } else { + /* XXX - no broadcast addresses in IPv6 */ + errno = EINVAL; + return (-1); + } + return (0); +} + +char * +addr_ntop(const struct addr *src, char *dst, size_t size) +{ + if (src->addr_type == ADDR_TYPE_IP && size >= 20) { + if (ip_ntop(&src->addr_ip, dst, size) != NULL) { + if (src->addr_bits != IP_ADDR_BITS) + sprintf(dst + strlen(dst), "/%d", + src->addr_bits); + return (dst); + } + } else if (src->addr_type == ADDR_TYPE_IP6 && size >= 42) { + if (ip6_ntop(&src->addr_ip6, dst, size) != NULL) { + if (src->addr_bits != IP6_ADDR_BITS) + sprintf(dst + strlen(dst), "/%d", + src->addr_bits); + return (dst); + } + } else if (src->addr_type == ADDR_TYPE_ETH && size >= 18) { + if (src->addr_bits == ETH_ADDR_BITS) + return (eth_ntop(&src->addr_eth, dst, size)); + } + errno = EINVAL; + return (NULL); +} + +int +addr_pton(const char *src, struct addr *dst) +{ + struct hostent *hp; + char *ep, tmp[300]; + long bits = -1; + int i; + + for (i = 0; i < (int)sizeof(tmp) - 1; i++) { + if (src[i] == '/') { + tmp[i] = '\0'; + if (strchr(&src[i + 1], '.')) { + uint32_t m; + uint16_t b; + /* XXX - mask is specified like /255.0.0.0 */ + if (ip_pton(&src[i + 1], &m) != 0) { + errno = EINVAL; + return (-1); + } + addr_mtob(&m, sizeof(m), &b); + bits = b; + } else { + bits = strtol(&src[i + 1], &ep, 10); + if (ep == src || *ep != '\0' || bits < 0) { + errno = EINVAL; + return (-1); + } + } + break; + } else if ((tmp[i] = src[i]) == '\0') + break; + } + if (ip_pton(tmp, &dst->addr_ip) == 0) { + dst->addr_type = ADDR_TYPE_IP; + dst->addr_bits = IP_ADDR_BITS; + } else if (eth_pton(tmp, &dst->addr_eth) == 0) { + dst->addr_type = ADDR_TYPE_ETH; + dst->addr_bits = ETH_ADDR_BITS; + } else if (ip6_pton(tmp, &dst->addr_ip6) == 0) { + dst->addr_type = ADDR_TYPE_IP6; + dst->addr_bits = IP6_ADDR_BITS; + } else if ((hp = gethostbyname(tmp)) != NULL) { + memcpy(&dst->addr_ip, hp->h_addr, IP_ADDR_LEN); + dst->addr_type = ADDR_TYPE_IP; + dst->addr_bits = IP_ADDR_BITS; + } else { + errno = EINVAL; + return (-1); + } + if (bits >= 0) { + if (bits > dst->addr_bits) { + errno = EINVAL; + return (-1); + } + dst->addr_bits = (uint16_t)bits; + } + return (0); +} + +char * +addr_ntoa(const struct addr *a) +{ + static char *p, buf[BUFSIZ]; + char *q = NULL; + + if (p == NULL || p > buf + sizeof(buf) - 64 /* XXX */) + p = buf; + + if (addr_ntop(a, p, (buf + sizeof(buf)) - p) != NULL) { + q = p; + p += strlen(p) + 1; + } + return (q); +} + +int +addr_ntos(const struct addr *a, struct sockaddr *sa) +{ + union sockunion *so = (union sockunion *)sa; + + switch (a->addr_type) { + case ADDR_TYPE_ETH: +#ifdef HAVE_NET_IF_DL_H + memset(&so->sdl, 0, sizeof(so->sdl)); +# ifdef HAVE_SOCKADDR_SA_LEN + so->sdl.sdl_len = sizeof(so->sdl); +# endif +# ifdef AF_LINK + so->sdl.sdl_family = AF_LINK; +# else + so->sdl.sdl_family = AF_UNSPEC; +# endif + so->sdl.sdl_alen = ETH_ADDR_LEN; + memcpy(LLADDR(&so->sdl), &a->addr_eth, ETH_ADDR_LEN); +#else + memset(sa, 0, sizeof(*sa)); +# ifdef AF_LINK + sa->sa_family = AF_LINK; +# else + sa->sa_family = AF_UNSPEC; +# endif + memcpy(sa->sa_data, &a->addr_eth, ETH_ADDR_LEN); +#endif + break; +#ifdef HAVE_SOCKADDR_IN6 + case ADDR_TYPE_IP6: + memset(&so->sin6, 0, sizeof(so->sin6)); +#ifdef HAVE_SOCKADDR_SA_LEN + so->sin6.sin6_len = sizeof(so->sin6); +#endif + so->sin6.sin6_family = AF_INET6; + memcpy(&so->sin6.sin6_addr, &a->addr_ip6, IP6_ADDR_LEN); + break; +#endif + case ADDR_TYPE_IP: + memset(&so->sin, 0, sizeof(so->sin)); +#ifdef HAVE_SOCKADDR_SA_LEN + so->sin.sin_len = sizeof(so->sin); +#endif + so->sin.sin_family = AF_INET; + so->sin.sin_addr.s_addr = a->addr_ip; + break; + default: + errno = EINVAL; + return (-1); + } + return (0); +} + +int +addr_ston(const struct sockaddr *sa, struct addr *a) +{ + union sockunion *so = (union sockunion *)sa; + + memset(a, 0, sizeof(*a)); + + switch (sa->sa_family) { +#ifdef HAVE_NET_IF_DL_H +# ifdef AF_LINK + case AF_LINK: + if (so->sdl.sdl_alen != ETH_ADDR_LEN) { + errno = EINVAL; + return (-1); + } + a->addr_type = ADDR_TYPE_ETH; + a->addr_bits = ETH_ADDR_BITS; + memcpy(&a->addr_eth, LLADDR(&so->sdl), ETH_ADDR_LEN); + break; +# endif +#endif + case AF_UNSPEC: + case ARP_HRD_ETH: /* XXX- Linux arp(7) */ + case ARP_HRD_APPLETALK: /* AppleTalk DDP */ + case ARP_HRD_INFINIBAND: /* InfiniBand */ + case ARP_HDR_IEEE80211: /* IEEE 802.11 */ + case ARP_HRD_IEEE80211_PRISM: /* IEEE 802.11 + prism header */ + case ARP_HRD_IEEE80211_RADIOTAP: /* IEEE 802.11 + radiotap header */ + a->addr_type = ADDR_TYPE_ETH; + a->addr_bits = ETH_ADDR_BITS; + memcpy(&a->addr_eth, sa->sa_data, ETH_ADDR_LEN); + break; + +#ifdef AF_RAW + case AF_RAW: /* XXX - IRIX raw(7f) */ + a->addr_type = ADDR_TYPE_ETH; + a->addr_bits = ETH_ADDR_BITS; + memcpy(&a->addr_eth, so->sr.sr_addr, ETH_ADDR_LEN); + break; +#endif +#ifdef HAVE_SOCKADDR_IN6 + case AF_INET6: + a->addr_type = ADDR_TYPE_IP6; + a->addr_bits = IP6_ADDR_BITS; + memcpy(&a->addr_ip6, &so->sin6.sin6_addr, IP6_ADDR_LEN); + break; +#endif + case AF_INET: + a->addr_type = ADDR_TYPE_IP; + a->addr_bits = IP_ADDR_BITS; + a->addr_ip = so->sin.sin_addr.s_addr; + break; + case ARP_HRD_VOID: + memset(&a->addr_eth, 0, ETH_ADDR_LEN); + break; + default: + errno = EINVAL; + return (-1); + } + return (0); +} + +int +addr_btos(uint16_t bits, struct sockaddr *sa) +{ + union sockunion *so = (union sockunion *)sa; + +#ifdef HAVE_SOCKADDR_IN6 + if (bits > IP_ADDR_BITS && bits <= IP6_ADDR_BITS) { + memset(&so->sin6, 0, sizeof(so->sin6)); +#ifdef HAVE_SOCKADDR_SA_LEN + so->sin6.sin6_len = IP6_ADDR_LEN + (bits / 8) + (bits % 8); +#endif + so->sin6.sin6_family = AF_INET6; + return (addr_btom(bits, &so->sin6.sin6_addr, IP6_ADDR_LEN)); + } else +#endif + if (bits <= IP_ADDR_BITS) { + memset(&so->sin, 0, sizeof(so->sin)); +#ifdef HAVE_SOCKADDR_SA_LEN + so->sin.sin_len = IP_ADDR_LEN + (bits / 8) + (bits % 8); +#endif + so->sin.sin_family = AF_INET; + return (addr_btom(bits, &so->sin.sin_addr, IP_ADDR_LEN)); + } + errno = EINVAL; + return (-1); +} + +int +addr_stob(const struct sockaddr *sa, uint16_t *bits) +{ + union sockunion *so = (union sockunion *)sa; + int i, j, len; + uint16_t n; + u_char *p; + +#ifdef HAVE_SOCKADDR_IN6 + if (sa->sa_family == AF_INET6) { + p = (u_char *)&so->sin6.sin6_addr; +#ifdef HAVE_SOCKADDR_SA_LEN + len = sa->sa_len - ((void *) p - (void *) sa); + /* Handles the special case of sa->sa_len == 0. */ + if (len < 0) + len = 0; + else if (len > IP6_ADDR_LEN) + len = IP6_ADDR_LEN; +#else + len = IP6_ADDR_LEN; +#endif + } else +#endif + { + p = (u_char *)&so->sin.sin_addr.s_addr; +#ifdef HAVE_SOCKADDR_SA_LEN + len = sa->sa_len - ((void *) p - (void *) sa); + /* Handles the special case of sa->sa_len == 0. */ + if (len < 0) + len = 0; + else if (len > IP_ADDR_LEN) + len = IP_ADDR_LEN; +#else + len = IP_ADDR_LEN; +#endif + } + for (n = i = 0; i < len; i++, n += 8) { + if (p[i] != 0xff) + break; + } + if (i != len && p[i]) { + for (j = 7; j > 0; j--, n++) { + if ((p[i] & (1 << j)) == 0) + break; + } + } + *bits = n; + + return (0); +} + +int +addr_btom(uint16_t bits, void *mask, size_t size) +{ + int net, host; + u_char *p; + + if (size == IP_ADDR_LEN) { + if (bits > IP_ADDR_BITS) { + errno = EINVAL; + return (-1); + } + *(uint32_t *)mask = bits ? + htonl(~(uint32_t)0 << (IP_ADDR_BITS - bits)) : 0; + } else { + if (size * 8 < bits) { + errno = EINVAL; + return (-1); + } + p = (u_char *)mask; + + if ((net = bits / 8) > 0) + memset(p, 0xff, net); + + if ((host = bits % 8) > 0) { + p[net] = 0xff << (8 - host); + memset(&p[net + 1], 0, size - net - 1); + } else + memset(&p[net], 0, size - net); + } + return (0); +} + +int +addr_mtob(const void *mask, size_t size, uint16_t *bits) +{ + uint16_t n; + u_char *p; + int i, j; + + p = (u_char *)mask; + + for (n = i = 0; i < (int)size; i++, n += 8) { + if (p[i] != 0xff) + break; + } + if (i != (int)size && p[i]) { + for (j = 7; j > 0; j--, n++) { + if ((p[i] & (1 << j)) == 0) + break; + } + } + *bits = n; + + return (0); +} diff --git a/libdnet-stripped/src/arp-bsd.c b/libdnet-stripped/src/arp-bsd.c new file mode 100644 index 0000000..e2beb25 --- /dev/null +++ b/libdnet-stripped/src/arp-bsd.c @@ -0,0 +1,323 @@ +/* + * arp-bsd.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: arp-bsd.c 539 2005-01-23 07:36:54Z dugsong $ + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifdef HAVE_STREAMS_ROUTE +#include <sys/stream.h> +#include <sys/stropts.h> +#endif + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct arp_handle { + int fd; + int seq; +}; + +struct arpmsg { + struct rt_msghdr rtm; + u_char addrs[256]; +}; + +arp_t * +arp_open(void) +{ + arp_t *arp; + + if ((arp = calloc(1, sizeof(*arp))) != NULL) { +#ifdef HAVE_STREAMS_ROUTE + if ((arp->fd = open("/dev/route", O_RDWR, 0)) < 0) +#else + if ((arp->fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) +#endif + return (arp_close(arp)); + } + return (arp); +} + +static int +arp_msg(arp_t *arp, struct arpmsg *msg) +{ + struct arpmsg smsg; + int len, i = 0; + pid_t pid; + + msg->rtm.rtm_version = RTM_VERSION; + msg->rtm.rtm_seq = ++arp->seq; + memcpy(&smsg, msg, sizeof(smsg)); + +#ifdef HAVE_STREAMS_ROUTE + return (ioctl(arp->fd, RTSTR_SEND, &msg->rtm)); +#else + if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) { + if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE) + return (-1); + } + pid = getpid(); + + /* XXX - should we only read RTM_GET responses here? */ + while ((len = read(arp->fd, msg, sizeof(*msg))) > 0) { + if (len < (int)sizeof(msg->rtm)) + return (-1); + + if (msg->rtm.rtm_pid == pid) { + if (msg->rtm.rtm_seq == arp->seq) + break; + continue; + } else if ((i++ % 2) == 0) + continue; + + /* Repeat request. */ + if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) { + if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE) + return (-1); + } + } + if (len < 0) + return (-1); + + return (0); +#endif +} + +int +arp_add(arp_t *arp, const struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + int index, type; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP || + entry->arp_ha.addr_type != ADDR_TYPE_ETH) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa)) { + errno = EADDRNOTAVAIL; + return (-1); + } + if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) { + if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 || + (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) { + errno = EADDRINUSE; + return (-1); + } + } + if (sa->sa_family != AF_LINK) { + errno = EADDRNOTAVAIL; + return (-1); + } else { + index = ((struct sockaddr_dl *)sa)->sdl_index; + type = ((struct sockaddr_dl *)sa)->sdl_type; + } + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0 || + addr_ntos(&entry->arp_ha, sa) < 0) + return (-1); + + ((struct sockaddr_dl *)sa)->sdl_index = index; + ((struct sockaddr_dl *)sa)->sdl_type = type; + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_ADD; + msg.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; + msg.rtm.rtm_inits = RTV_EXPIRE; + msg.rtm.rtm_flags = RTF_HOST | RTF_STATIC; +#ifdef HAVE_SOCKADDR_SA_LEN + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sin->sin_len + sa->sa_len; +#else + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin) + sizeof(*sa); +#endif + return (arp_msg(arp, &msg)); +} + +int +arp_delete(arp_t *arp, const struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa)) { + errno = ESRCH; + return (-1); + } + if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) { + if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 || + (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) { + errno = EADDRINUSE; + return (-1); + } + } + if (sa->sa_family != AF_LINK) { + errno = ESRCH; + return (-1); + } + msg.rtm.rtm_type = RTM_DELETE; + + return (arp_msg(arp, &msg)); +} + +int +arp_get(arp_t *arp, struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_flags = RTF_LLINFO; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa) || + sin->sin_addr.s_addr != entry->arp_pa.addr_ip || + sa->sa_family != AF_LINK) { + errno = ESRCH; + return (-1); + } + if (addr_ston(sa, &entry->arp_ha) < 0) + return (-1); + + return (0); +} + +#ifdef HAVE_SYS_SYSCTL_H +int +arp_loop(arp_t *arp, arp_handler callback, void *arg) +{ + struct arp_entry entry; + struct rt_msghdr *rtm; + struct sockaddr_in *sin; + struct sockaddr *sa; + char *buf, *lim, *next; + size_t len; + int ret, mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_FLAGS, RTF_LLINFO }; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return (-1); + + if (len == 0) + return (0); + + if ((buf = malloc(len)) == NULL) + return (-1); + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return (-1); + } + lim = buf + len; + ret = 0; + + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_in *)(rtm + 1); + sa = (struct sockaddr *)(sin + 1); + + if (addr_ston((struct sockaddr *)sin, &entry.arp_pa) < 0 || + addr_ston(sa, &entry.arp_ha) < 0) + continue; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + free(buf); + + return (ret); +} +#else +int +arp_loop(arp_t *arp, arp_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} +#endif + +arp_t * +arp_close(arp_t *arp) +{ + if (arp != NULL) { + if (arp->fd >= 0) + close(arp->fd); + free(arp); + } + return (NULL); +} diff --git a/libdnet-stripped/src/arp-ioctl.c b/libdnet-stripped/src/arp-ioctl.c new file mode 100644 index 0000000..31b9f8c --- /dev/null +++ b/libdnet-stripped/src/arp-ioctl.c @@ -0,0 +1,489 @@ +/* + * arp-ioctl.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: arp-ioctl.c 554 2005-02-09 22:31:00Z dugsong $ + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef HAVE_STREAMS_MIB2 +# include <sys/sockio.h> +# include <sys/stream.h> +# include <sys/tihdr.h> +# include <sys/tiuser.h> +# include <inet/common.h> +# include <inet/mib2.h> +# include <inet/ip.h> +# undef IP_ADDR_LEN +#elif defined(HAVE_SYS_MIB_H) +# include <sys/mib.h> +#endif + +#include <net/if.h> +#include <net/if_arp.h> +#ifdef HAVE_STREAMS_MIB2 +# include <netinet/in.h> +# include <stropts.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +#ifdef HAVE_LINUX_PROCFS +#define PROC_ARP_FILE "/proc/net/arp" +#endif + +struct arp_handle { + int fd; +#ifdef HAVE_ARPREQ_ARP_DEV + intf_t *intf; +#endif +}; + +arp_t * +arp_open(void) +{ + arp_t *a; + + if ((a = calloc(1, sizeof(*a))) != NULL) { +#ifdef HAVE_STREAMS_MIB2 + if ((a->fd = open(IP_DEV_NAME, O_RDWR)) < 0) +#elif defined(HAVE_STREAMS_ROUTE) + if ((a->fd = open("/dev/route", O_WRONLY, 0)) < 0) +#else + if ((a->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) +#endif + return (arp_close(a)); +#ifdef HAVE_ARPREQ_ARP_DEV + if ((a->intf = intf_open()) == NULL) + return (arp_close(a)); +#endif + } + return (a); +} + +#ifdef HAVE_ARPREQ_ARP_DEV +static int +_arp_set_dev(const struct intf_entry *entry, void *arg) +{ + struct arpreq *ar = (struct arpreq *)arg; + struct addr dst; + uint32_t mask; + + if (entry->intf_type == INTF_TYPE_ETH && + entry->intf_addr.addr_type == ADDR_TYPE_IP) { + addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN); + addr_ston((struct sockaddr *)&ar->arp_pa, &dst); + + if ((entry->intf_addr.addr_ip & mask) == + (dst.addr_ip & mask)) { + strlcpy(ar->arp_dev, entry->intf_name, + sizeof(ar->arp_dev)); + return (1); + } + } + return (0); +} +#endif + +int +arp_add(arp_t *a, const struct arp_entry *entry) +{ + struct arpreq ar; + + memset(&ar, 0, sizeof(ar)); + + if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0) + return (-1); + + /* XXX - see arp(7) for details... */ +#ifdef __linux__ + if (addr_ntos(&entry->arp_ha, &ar.arp_ha) < 0) + return (-1); + ar.arp_ha.sa_family = ARP_HRD_ETH; +#else + /* XXX - Solaris, HP-UX, IRIX, other Mentat stacks? */ + ar.arp_ha.sa_family = AF_UNSPEC; + memcpy(ar.arp_ha.sa_data, &entry->arp_ha.addr_eth, ETH_ADDR_LEN); +#endif + +#ifdef HAVE_ARPREQ_ARP_DEV + if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) { + errno = ESRCH; + return (-1); + } +#endif + ar.arp_flags = ATF_PERM | ATF_COM; +#ifdef hpux + /* XXX - screwy extended arpreq struct */ + { + struct sockaddr_in *sin; + + ar.arp_hw_addr_len = ETH_ADDR_LEN; + sin = (struct sockaddr_in *)&ar.arp_pa_mask; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = IP_ADDR_BROADCAST; + } +#endif + if (ioctl(a->fd, SIOCSARP, &ar) < 0) + return (-1); + +#ifdef HAVE_STREAMS_MIB2 + /* XXX - force entry into ipNetToMediaTable. */ + { + struct sockaddr_in sin; + int fd; + + addr_ntos(&entry->arp_pa, (struct sockaddr *)&sin); + sin.sin_port = htons(666); + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (-1); + + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(fd); + return (-1); + } + write(fd, NULL, 0); + close(fd); + } +#endif + return (0); +} + +int +arp_delete(arp_t *a, const struct arp_entry *entry) +{ + struct arpreq ar; + + memset(&ar, 0, sizeof(ar)); + + if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0) + return (-1); + + if (ioctl(a->fd, SIOCDARP, &ar) < 0) + return (-1); + + return (0); +} + +int +arp_get(arp_t *a, struct arp_entry *entry) +{ + struct arpreq ar; + + memset(&ar, 0, sizeof(ar)); + + if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0) + return (-1); + +#ifdef HAVE_ARPREQ_ARP_DEV + if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) { + errno = ESRCH; + return (-1); + } +#endif + if (ioctl(a->fd, SIOCGARP, &ar) < 0) + return (-1); + + if ((ar.arp_flags & ATF_COM) == 0) { + errno = ESRCH; + return (-1); + } + return (addr_ston(&ar.arp_ha, &entry->arp_ha)); +} + +#ifdef HAVE_LINUX_PROCFS +int +arp_loop(arp_t *a, arp_handler callback, void *arg) +{ + FILE *fp; + struct arp_entry entry; + char buf[BUFSIZ], ipbuf[100], macbuf[100], maskbuf[100], devbuf[100]; + int i, type, flags, ret; + + if ((fp = fopen(PROC_ARP_FILE, "r")) == NULL) + return (-1); + + ret = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + i = sscanf(buf, "%s 0x%x 0x%x %99s %99s %99s\n", + ipbuf, &type, &flags, macbuf, maskbuf, devbuf); + + if (i < 4 || (flags & ATF_COM) == 0) + continue; + + if (addr_aton(ipbuf, &entry.arp_pa) == 0 && + addr_aton(macbuf, &entry.arp_ha) == 0) { + if ((ret = callback(&entry, arg)) != 0) + break; + } + } + if (ferror(fp)) { + fclose(fp); + return (-1); + } + fclose(fp); + + return (ret); +} +#elif defined (HAVE_STREAMS_MIB2) +int +arp_loop(arp_t *r, arp_handler callback, void *arg) +{ + struct arp_entry entry; + struct strbuf msg; + struct T_optmgmt_req *tor; + struct T_optmgmt_ack *toa; + struct T_error_ack *tea; + struct opthdr *opt; + mib2_ipNetToMediaEntry_t *arp, *arpend; + u_char buf[8192]; + int flags, rc, atable, ret; + + tor = (struct T_optmgmt_req *)buf; + toa = (struct T_optmgmt_ack *)buf; + tea = (struct T_error_ack *)buf; + + tor->PRIM_type = T_OPTMGMT_REQ; + tor->OPT_offset = sizeof(*tor); + tor->OPT_length = sizeof(*opt); + tor->MGMT_flags = T_CURRENT; + + opt = (struct opthdr *)(tor + 1); + opt->level = MIB2_IP; + opt->name = opt->len = 0; + + msg.maxlen = sizeof(buf); + msg.len = sizeof(*tor) + sizeof(*opt); + msg.buf = buf; + + if (putmsg(r->fd, &msg, NULL, 0) < 0) + return (-1); + + opt = (struct opthdr *)(toa + 1); + msg.maxlen = sizeof(buf); + + for (;;) { + flags = 0; + if ((rc = getmsg(r->fd, &msg, NULL, &flags)) < 0) + return (-1); + + /* See if we're finished. */ + if (rc == 0 && + msg.len >= sizeof(*toa) && + toa->PRIM_type == T_OPTMGMT_ACK && + toa->MGMT_flags == T_SUCCESS && opt->len == 0) + break; + + if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK) + return (-1); + + if (rc != MOREDATA || msg.len < (int)sizeof(*toa) || + toa->PRIM_type != T_OPTMGMT_ACK || + toa->MGMT_flags != T_SUCCESS) + return (-1); + + atable = (opt->level == MIB2_IP && opt->name == MIB2_IP_22); + + msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*arp)); + msg.len = 0; + flags = 0; + + do { + rc = getmsg(r->fd, NULL, &msg, &flags); + + if (rc != 0 && rc != MOREDATA) + return (-1); + + if (!atable) + continue; + + arp = (mib2_ipNetToMediaEntry_t *)msg.buf; + arpend = (mib2_ipNetToMediaEntry_t *) + (msg.buf + msg.len); + + entry.arp_pa.addr_type = ADDR_TYPE_IP; + entry.arp_pa.addr_bits = IP_ADDR_BITS; + + entry.arp_ha.addr_type = ADDR_TYPE_ETH; + entry.arp_ha.addr_bits = ETH_ADDR_BITS; + + for ( ; arp < arpend; arp++) { + entry.arp_pa.addr_ip = + arp->ipNetToMediaNetAddress; + + memcpy(&entry.arp_ha.addr_eth, + arp->ipNetToMediaPhysAddress.o_bytes, + ETH_ADDR_LEN); + + if ((ret = callback(&entry, arg)) != 0) + return (ret); + } + } while (rc == MOREDATA); + } + return (0); +} +#elif defined(HAVE_SYS_MIB_H) +#define MAX_ARPENTRIES 512 /* XXX */ + +int +arp_loop(arp_t *r, arp_handler callback, void *arg) +{ + struct nmparms nm; + struct arp_entry entry; + mib_ipNetToMediaEnt arpentries[MAX_ARPENTRIES]; + int fd, i, n, ret; + + if ((fd = open_mib("/dev/ip", O_RDWR, 0 /* XXX */, 0)) < 0) + return (-1); + + nm.objid = ID_ipNetToMediaTable; + nm.buffer = arpentries; + n = sizeof(arpentries); + nm.len = &n; + + if (get_mib_info(fd, &nm) < 0) { + close_mib(fd); + return (-1); + } + close_mib(fd); + + entry.arp_pa.addr_type = ADDR_TYPE_IP; + entry.arp_pa.addr_bits = IP_ADDR_BITS; + + entry.arp_ha.addr_type = ADDR_TYPE_ETH; + entry.arp_ha.addr_bits = ETH_ADDR_BITS; + + n /= sizeof(*arpentries); + ret = 0; + + for (i = 0; i < n; i++) { + if (arpentries[i].Type == INTM_INVALID || + arpentries[i].PhysAddr.o_length != ETH_ADDR_LEN) + continue; + + entry.arp_pa.addr_ip = arpentries[i].NetAddr; + memcpy(&entry.arp_ha.addr_eth, arpentries[i].PhysAddr.o_bytes, + ETH_ADDR_LEN); + + if ((ret = callback(&entry, arg)) != 0) + break; + } + return (ret); +} +#elif defined(HAVE_NET_RADIX_H) && !defined(_AIX) +/* XXX - Tru64, others? */ +#include <netinet/if_ether.h> +#include <nlist.h> + +static int +_kread(int fd, void *addr, void *buf, int len) +{ + if (lseek(fd, (off_t)addr, SEEK_SET) == (off_t)-1L) + return (-1); + return (read(fd, buf, len) == len ? 0 : -1); +} + +static int +_radix_walk(int fd, struct radix_node *rn, arp_handler callback, void *arg) +{ + struct radix_node rnode; + struct rtentry rt; + struct sockaddr_in sin; + struct arptab at; + struct arp_entry entry; + int ret = 0; + again: + _kread(fd, rn, &rnode, sizeof(rnode)); + if (rnode.rn_b < 0) { + if (!(rnode.rn_flags & RNF_ROOT)) { + _kread(fd, rn, &rt, sizeof(rt)); + _kread(fd, rt_key(&rt), &sin, sizeof(sin)); + addr_ston((struct sockaddr *)&sin, &entry.arp_pa); + _kread(fd, rt.rt_llinfo, &at, sizeof(at)); + if (at.at_flags & ATF_COM) { + addr_pack(&entry.arp_ha, ADDR_TYPE_ETH, + ETH_ADDR_BITS, at.at_hwaddr, ETH_ADDR_LEN); + if ((ret = callback(&entry, arg)) != 0) + return (ret); + } + } + if ((rn = rnode.rn_dupedkey)) + goto again; + } else { + rn = rnode.rn_r; + if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0) + return (ret); + if ((ret = _radix_walk(fd, rn, callback, arg)) != 0) + return (ret); + } + return (ret); +} + +int +arp_loop(arp_t *r, arp_handler callback, void *arg) +{ + struct ifnet *ifp, ifnet; + struct ifnet_arp_cache_head ifarp; + struct radix_node_head *head; + + struct nlist nl[2]; + int fd, ret = 0; + + memset(nl, 0, sizeof(nl)); + nl[0].n_name = "ifnet"; + + if (knlist(nl) < 0 || nl[0].n_type == 0 || + (fd = open("/dev/kmem", O_RDONLY, 0)) < 0) + return (-1); + + for (ifp = (struct ifnet *)nl[0].n_value; + ifp != NULL; ifp = ifnet.if_next) { + _kread(fd, ifp, &ifnet, sizeof(ifnet)); + if (ifnet.if_arp_cache_head != NULL) { + _kread(fd, ifnet.if_arp_cache_head, + &ifarp, sizeof(ifarp)); + /* XXX - only ever one rnh, only ever AF_INET. */ + if ((ret = _radix_walk(fd, ifarp.arp_cache_head.rnh_treetop, + callback, arg)) != 0) + break; + } + } + close(fd); + return (ret); +} +#else +int +arp_loop(arp_t *a, arp_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} +#endif + +arp_t * +arp_close(arp_t *a) +{ + if (a != NULL) { + if (a->fd >= 0) + close(a->fd); +#ifdef HAVE_ARPREQ_ARP_DEV + if (a->intf != NULL) + intf_close(a->intf); +#endif + free(a); + } + return (NULL); +} diff --git a/libdnet-stripped/src/arp-none.c b/libdnet-stripped/src/arp-none.c new file mode 100644 index 0000000..293f2dd --- /dev/null +++ b/libdnet-stripped/src/arp-none.c @@ -0,0 +1,58 @@ +/* + * arp-none.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: arp-none.c 252 2002-02-02 04:15:57Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +arp_t * +arp_open(void) +{ + errno = ENOSYS; + return (NULL); +} + +int +arp_add(arp_t *a, const struct arp_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +arp_delete(arp_t *a, const struct arp_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +arp_get(arp_t *a, struct arp_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +arp_loop(arp_t *a, arp_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} + +arp_t * +arp_close(arp_t *a) +{ + return (NULL); +} diff --git a/libdnet-stripped/src/arp-win32.c b/libdnet-stripped/src/arp-win32.c new file mode 100644 index 0000000..31bc565 --- /dev/null +++ b/libdnet-stripped/src/arp-win32.c @@ -0,0 +1,163 @@ +/* + * arp-win32.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: arp-win32.c 539 2005-01-23 07:36:54Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <ws2tcpip.h> +#include <iphlpapi.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +struct arp_handle { + MIB_IPNET_TABLE2 *iptable; +}; + +arp_t * +arp_open(void) +{ + return (calloc(1, sizeof(arp_t))); +} + +int +arp_add(arp_t *arp, const struct arp_entry *entry) +{ + MIB_IPFORWARDROW ipfrow; + MIB_IPNETROW iprow; + + if (GetBestRoute(entry->arp_pa.addr_ip, + IP_ADDR_ANY, &ipfrow) != NO_ERROR) + return (-1); + + iprow.dwIndex = ipfrow.dwForwardIfIndex; + iprow.dwPhysAddrLen = ETH_ADDR_LEN; + memcpy(iprow.bPhysAddr, &entry->arp_ha.addr_eth, ETH_ADDR_LEN); + iprow.dwAddr = entry->arp_pa.addr_ip; + iprow.dwType = 4; /* XXX - static */ + + if (CreateIpNetEntry(&iprow) != NO_ERROR) + return (-1); + + return (0); +} + +int +arp_delete(arp_t *arp, const struct arp_entry *entry) +{ + MIB_IPFORWARDROW ipfrow; + MIB_IPNETROW iprow; + + if (GetBestRoute(entry->arp_pa.addr_ip, + IP_ADDR_ANY, &ipfrow) != NO_ERROR) + return (-1); + + memset(&iprow, 0, sizeof(iprow)); + iprow.dwIndex = ipfrow.dwForwardIfIndex; + iprow.dwAddr = entry->arp_pa.addr_ip; + + if (DeleteIpNetEntry(&iprow) != NO_ERROR) { + errno = ENXIO; + return (-1); + } + return (0); +} + +static int +_arp_get_entry(const struct arp_entry *entry, void *arg) +{ + struct arp_entry *e = (struct arp_entry *)arg; + + if (addr_cmp(&entry->arp_pa, &e->arp_pa) == 0) { + memcpy(&e->arp_ha, &entry->arp_ha, sizeof(e->arp_ha)); + return (1); + } + return (0); +} + +int +arp_get(arp_t *arp, struct arp_entry *entry) +{ + if (arp_loop(arp, _arp_get_entry, entry) != 1) { + errno = ENXIO; + SetLastError(ERROR_NO_DATA); + return (-1); + } + return (0); +} + +int +arp_loop(arp_t *arp, arp_handler callback, void *arg) +{ + struct arp_entry entry; + int ret; + + if (arp->iptable) + FreeMibTable(arp->iptable); + ret = GetIpNetTable2(AF_UNSPEC, &arp->iptable); + switch (ret) { + case NO_ERROR: + break; + case ERROR_NOT_FOUND: + return 0; + break; + default: + return -1; + break; + } + + entry.arp_ha.addr_type = ADDR_TYPE_ETH; + entry.arp_ha.addr_bits = ETH_ADDR_BITS; + + for (ULONG i = 0; i < arp->iptable->NumEntries; i++) { + MIB_IPNET_ROW2 *row = &arp->iptable->Table[i]; + if (row->PhysicalAddressLength != ETH_ADDR_LEN || + row->IsUnreachable || + row->State < NlnsReachable) + continue; + switch (row->Address.si_family) { + case AF_INET: + entry.arp_pa.addr_type = ADDR_TYPE_IP; + entry.arp_pa.addr_bits = IP_ADDR_BITS; + entry.arp_pa.addr_ip = row->Address.Ipv4.sin_addr.S_un.S_addr; + break; + case AF_INET6: + entry.arp_pa.addr_type = ADDR_TYPE_IP6; + entry.arp_pa.addr_bits = IP6_ADDR_BITS; + memcpy(&entry.arp_pa.addr_ip6, + row->Address.Ipv6.sin6_addr.u.Byte, IP6_ADDR_LEN); + break; + default: + continue; + break; + } + memcpy(&entry.arp_ha.addr_eth, + row->PhysicalAddress, ETH_ADDR_LEN); + + if ((ret = (*callback)(&entry, arg)) != 0) + return (ret); + } + return (0); +} + +arp_t * +arp_close(arp_t *arp) +{ + if (arp != NULL) { + if (arp->iptable != NULL) + FreeMibTable(arp->iptable); + free(arp); + } + return (NULL); +} diff --git a/libdnet-stripped/src/blob.c b/libdnet-stripped/src/blob.c new file mode 100644 index 0000000..57ff0c3 --- /dev/null +++ b/libdnet-stripped/src/blob.c @@ -0,0 +1,458 @@ +/* + * blob.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: blob.c 615 2006-01-08 16:06:49Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +static void *(*bl_malloc)(size_t) = malloc; +static void *(*bl_realloc)(void *, size_t) = realloc; +static void (*bl_free)(void *) = free; +static int bl_size = BUFSIZ; + +static int fmt_D(int, int, blob_t *, va_list *); +static int fmt_H(int, int, blob_t *, va_list *); +static int fmt_b(int, int, blob_t *, va_list *); +static int fmt_c(int, int, blob_t *, va_list *); +static int fmt_d(int, int, blob_t *, va_list *); +static int fmt_h(int, int, blob_t *, va_list *); +static int fmt_s(int, int, blob_t *, va_list *); + +static void print_hexl(blob_t *); + +static blob_fmt_cb blob_ascii_fmt[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, fmt_D, NULL, NULL, NULL, + fmt_H, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, fmt_b, fmt_c, fmt_d, NULL, NULL, NULL, + fmt_h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, fmt_s, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +struct blob_printer { + char *name; + void (*print)(blob_t *); +} blob_printers[] = { + { "hexl", print_hexl }, + { NULL, NULL }, +}; + +blob_t * +blob_new(void) +{ + blob_t *b; + + if ((b = bl_malloc(sizeof(*b))) != NULL) { + b->off = b->end = 0; + b->size = bl_size; + if ((b->base = bl_malloc(b->size)) == NULL) { + bl_free(b); + b = NULL; + } + } + return (b); +} + +static int +blob_reserve(blob_t *b, int len) +{ + void *p; + int nsize; + + if (b->size < b->end + len) { + if (b->size == 0) + return (-1); + + if ((nsize = b->end + len) > bl_size) + nsize = ((nsize / bl_size) + 1) * bl_size; + + if ((p = bl_realloc(b->base, nsize)) == NULL) + return (-1); + + b->base = p; + b->size = nsize; + } + b->end += len; + + return (0); +} + +int +blob_read(blob_t *b, void *buf, int len) +{ + if (b->end - b->off < len) + len = b->end - b->off; + + memcpy(buf, b->base + b->off, len); + b->off += len; + + return (len); +} + +int +blob_write(blob_t *b, const void *buf, int len) +{ + if (b->off + len <= b->end || + blob_reserve(b, b->off + len - b->end) == 0) { + memcpy(b->base + b->off, (u_char *)buf, len); + b->off += len; + return (len); + } + return (-1); +} + +int +blob_insert(blob_t *b, const void *buf, int len) +{ + if (blob_reserve(b, len) == 0 && b->size) { + if (b->end - b->off > 0) + memmove( b->base + b->off + len, b->base + b->off, b->end - b->off); + memcpy(b->base + b->off, buf, len); + b->off += len; + return (len); + } + return (-1); +} + +int +blob_delete(blob_t *b, void *buf, int len) +{ + if (b->off + len <= b->end && b->size) { + if (buf != NULL) + memcpy(buf, b->base + b->off, len); + memmove(b->base + b->off, b->base + b->off + len, b->end - (b->off + len)); + b->end -= len; + return (len); + } + return (-1); +} + +static int +blob_fmt(blob_t *b, int pack, const char *fmt, va_list *ap) +{ + blob_fmt_cb fmt_cb; + char *p; + int len; + + for (p = (char *)fmt; *p != '\0'; p++) { + if (*p == '%') { + p++; + if (isdigit((int) (unsigned char) *p)) { + len = strtol(p, &p, 10); + } else if (*p == '*') { + len = va_arg(*ap, int); + p++; + } else + len = 0; + + if ((fmt_cb = blob_ascii_fmt[(int)*p]) == NULL) + return (-1); + + if ((*fmt_cb)(pack, len, b, ap) < 0) + return (-1); + } else { + if (pack) { + if (b->off + 1 < b->end || + blob_reserve(b, b->off + 1 - b->end) == 0) + b->base[b->off++] = *p; + else + return (-1); + } else { + if (b->base[b->off++] != *p) + return (-1); + } + } + } + return (0); +} + +int +blob_pack(blob_t *b, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + return (blob_fmt(b, 1, fmt, &ap)); +} + +int +blob_unpack(blob_t *b, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + return (blob_fmt(b, 0, fmt, &ap)); +} + +int +blob_seek(blob_t *b, int off, int whence) +{ + if (whence == SEEK_CUR) + off += b->off; + else if (whence == SEEK_END) + off += b->end; + + if (off < 0 || off > b->end) + return (-1); + + return ((b->off = off)); +} + +int +blob_index(blob_t *b, const void *buf, int len) +{ + int i; + + for (i = b->off; i <= b->end - len; i++) { + if (memcmp(b->base + i, buf, len) == 0) + return (i); + } + return (-1); +} + +int +blob_rindex(blob_t *b, const void *buf, int len) +{ + int i; + + for (i = b->end - len; i >= 0; i--) { + if (memcmp(b->base + i, buf, len) == 0) + return (i); + } + return (-1); +} + +int +blob_print(blob_t *b, char *style, int len) +{ + struct blob_printer *bp; + + for (bp = blob_printers; bp->name != NULL; bp++) { + if (strcmp(bp->name, style) == 0) + bp->print(b); + } + return (0); +} + +int +blob_sprint(blob_t *b, char *style, int len, char *dst, int size) +{ + return (0); +} + +blob_t * +blob_free(blob_t *b) +{ + if (b->size) + bl_free(b->base); + bl_free(b); + return (NULL); +} + +int +blob_register_alloc(size_t size, void *(bmalloc)(size_t), + void (*bfree)(void *), void *(*brealloc)(void *, size_t)) +{ + bl_size = size; + if (bmalloc != NULL) + bl_malloc = bmalloc; + if (bfree != NULL) + bl_free = bfree; + if (brealloc != NULL) + bl_realloc = brealloc; + return (0); +} + +int +blob_register_pack(char c, blob_fmt_cb fmt_cb) +{ + if (blob_ascii_fmt[(int)c] == NULL) { + blob_ascii_fmt[(int)c] = fmt_cb; + return (0); + } + return (-1); +} + +static int +fmt_D(int pack, int len, blob_t *b, va_list *ap) +{ + if (len) return (-1); + + if (pack) { + uint32_t n = va_arg(*ap, uint32_t); + n = htonl(n); + if (blob_write(b, &n, sizeof(n)) < 0) + return (-1); + } else { + uint32_t *n = va_arg(*ap, uint32_t *); + if (blob_read(b, n, sizeof(*n)) != sizeof(*n)) + return (-1); + *n = ntohl(*n); + } + return (0); +} + +static int +fmt_H(int pack, int len, blob_t *b, va_list *ap) +{ + if (len) return (-1); + + if (pack) { + uint16_t n = va_arg(*ap, int); + n = htons(n); + if (blob_write(b, &n, sizeof(n)) < 0) + return (-1); + } else { + uint16_t *n = va_arg(*ap, uint16_t *); + if (blob_read(b, n, sizeof(*n)) != sizeof(*n)) + return (-1); + *n = ntohs(*n); + } + return (0); +} + +static int +fmt_b(int pack, int len, blob_t *b, va_list *ap) +{ + void *p = va_arg(*ap, void *); + + if (len <= 0) return (-1); + + if (pack) + return (blob_write(b, p, len)); + else + return (blob_read(b, p, len)); +} + +static int +fmt_c(int pack, int len, blob_t *b, va_list *ap) +{ + if (len) return (-1); + + if (pack) { + uint8_t n = va_arg(*ap, int); + return (blob_write(b, &n, sizeof(n))); + } else { + uint8_t *n = va_arg(*ap, uint8_t *); + return (blob_read(b, n, sizeof(*n))); + } +} + +static int +fmt_d(int pack, int len, blob_t *b, va_list *ap) +{ + if (len) return (-1); + + if (pack) { + uint32_t n = va_arg(*ap, uint32_t); + return (blob_write(b, &n, sizeof(n))); + } else { + uint32_t *n = va_arg(*ap, uint32_t *); + return (blob_read(b, n, sizeof(*n))); + } +} + +static int +fmt_h(int pack, int len, blob_t *b, va_list *ap) +{ + if (len) return (-1); + + if (pack) { + uint16_t n = va_arg(*ap, int); + return (blob_write(b, &n, sizeof(n))); + } else { + uint16_t *n = va_arg(*ap, uint16_t *); + return (blob_read(b, n, sizeof(*n))); + } +} + +static int +fmt_s(int pack, int len, blob_t *b, va_list *ap) +{ + char *p = va_arg(*ap, char *); + char c = '\0'; + int i, end; + + if (pack) { + if (len > 0) { + if ((c = p[len - 1]) != '\0') + p[len - 1] = '\0'; + } else + len = strlen(p) + 1; + + if (blob_write(b, p, len) > 0) { + if (c != '\0') + p[len - 1] = c; + return (len); + } + } else { + if (len <= 0) return (-1); + + if ((end = b->end - b->off) < len) + end = len; + + for (i = 0; i < end; i++) { + if ((p[i] = b->base[b->off + i]) == '\0') { + b->off += i + 1; + return (i); + } + } + } + return (-1); +} + +static void +print_hexl(blob_t *b) +{ + u_int i, j, jm, len; + u_char *p; + int c; + + p = b->base + b->off; + len = b->end - b->off; + + printf("\n"); + + for (i = 0; i < len; i += 0x10) { + printf(" %04x: ", (u_int)(i + b->off)); + jm = len - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + printf((j % 2) ? "%02x " : "%02x", (u_int)p[i + j]); + } + for (; j < 16; j++) { + printf((j % 2) ? " " : " "); + } + printf(" "); + + for (j = 0; j < jm; j++) { + c = p[i + j]; + printf("%c", isprint(c) ? c : '.'); + } + printf("\n"); + } +} diff --git a/libdnet-stripped/src/crc32ct.h b/libdnet-stripped/src/crc32ct.h new file mode 100644 index 0000000..8c3ac92 --- /dev/null +++ b/libdnet-stripped/src/crc32ct.h @@ -0,0 +1,83 @@ +/* + * crc32ct.h + * + * Public domain. + * + * $Id$ + */ + +#ifndef CRC32CT_H +#define CRC32CT_H + +#define CRC32C_POLY 0x1EDC6F41 +#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) + +static unsigned long crc_c[256] = { +0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, +0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, +0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, +0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, +0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, +0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, +0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, +0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, +0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, +0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, +0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, +0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, +0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, +0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, +0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, +0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, +0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, +0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, +0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, +0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, +0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, +0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, +0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, +0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, +0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, +0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, +0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, +0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, +0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, +0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, +0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, +0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, +0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, +0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, +0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, +0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, +0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, +0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, +0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, +0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, +0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, +0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, +0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, +0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, +0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, +0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, +0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, +0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, +0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, +0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, +0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, +0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, +0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, +0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, +0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, +0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, +0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, +0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, +0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, +0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, +0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, +0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, +0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, +0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, +}; + +#endif /* CRC32CT_H */ + diff --git a/libdnet-stripped/src/err.c b/libdnet-stripped/src/err.c new file mode 100644 index 0000000..cd201c3 --- /dev/null +++ b/libdnet-stripped/src/err.c @@ -0,0 +1,110 @@ +/* + * err.c + * + * Adapted from OpenBSD libc *err* *warn* code. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * Copyright (c) 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ + +#ifdef _WIN32 +#include <windows.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +void +err(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + va_end(ap); +#ifdef _WIN32 + (void)fprintf(stderr, "error %lu\n", GetLastError()); +#else + (void)fprintf(stderr, "%s\n", strerror(errno)); +#endif + exit(eval); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + va_end(ap); +#ifdef _WIN32 + (void)fprintf(stderr, "error %lu\n", GetLastError()); +#else + (void)fprintf(stderr, "%s\n", strerror(errno)); +#endif +} + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); + va_end(ap); + exit(eval); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); + va_end(ap); +} + diff --git a/libdnet-stripped/src/eth-bsd.c b/libdnet-stripped/src/eth-bsd.c new file mode 100644 index 0000000..1f4bde6 --- /dev/null +++ b/libdnet-stripped/src/eth-bsd.c @@ -0,0 +1,172 @@ +/* + * eth-bsd.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: eth-bsd.c 630 2006-02-02 04:17:39Z dugsong $ + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/time.h> +#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_ROUTE_RT_MSGHDR) +#include <sys/sysctl.h> +#include <net/route.h> +#include <net/if_dl.h> +#endif +#include <net/bpf.h> +#include <net/if.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct eth_handle { + int fd; + char device[16]; +}; + +eth_t * +eth_open(const char *device) +{ + struct ifreq ifr; + char file[32]; + eth_t *e; + int i; + + if ((e = calloc(1, sizeof(*e))) != NULL) { + for (i = 0; i < 128; i++) { + snprintf(file, sizeof(file), "/dev/bpf%d", i); + /* This would be O_WRONLY, but Mac OS X 10.6 has a bug + where that prevents other users of the interface + from seeing incoming traffic, even in other + processes. */ + e->fd = open(file, O_RDWR); + if (e->fd != -1 || errno != EBUSY) + break; + } + if (e->fd < 0) + return (eth_close(e)); + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(e->fd, BIOCSETIF, (char *)&ifr) < 0) + return (eth_close(e)); +#ifdef BIOCSHDRCMPLT + i = 1; + if (ioctl(e->fd, BIOCSHDRCMPLT, &i) < 0) + return (eth_close(e)); +#endif + strlcpy(e->device, device, sizeof(e->device)); + } + return (e); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + return (write(e->fd, buf, len)); +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + free(e); + } + return (NULL); +} + +#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_ROUTE_RT_MSGHDR) +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + struct if_msghdr *ifm; + struct sockaddr_dl *sdl; + struct addr ha; + u_char *p, *buf; + size_t len; + int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return (-1); + + if ((buf = malloc(len)) == NULL) + return (-1); + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return (-1); + } + for (p = buf; p < buf + len; p += ifm->ifm_msglen) { + ifm = (struct if_msghdr *)p; + sdl = (struct sockaddr_dl *)(ifm + 1); + + if (ifm->ifm_type != RTM_IFINFO || + (ifm->ifm_addrs & RTA_IFP) == 0) + continue; + + if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || + memcmp(sdl->sdl_data, e->device, sdl->sdl_nlen) != 0) + continue; + + if (addr_ston((struct sockaddr *)sdl, &ha) == 0) + break; + } + free(buf); + + if (p >= buf + len) { + errno = ESRCH; + return (-1); + } + memcpy(ea, &ha.addr_eth, sizeof(*ea)); + + return (0); +} +#else +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + errno = ENOSYS; + return (-1); +} +#endif + +#if defined(SIOCSIFLLADDR) +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + struct ifreq ifr; + struct addr ha; + + ha.addr_type = ADDR_TYPE_ETH; + ha.addr_bits = ETH_ADDR_BITS; + memcpy(&ha.addr_eth, ea, ETH_ADDR_LEN); + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, e->device, sizeof(ifr.ifr_name)); + addr_ntos(&ha, &ifr.ifr_addr); + + return (ioctl(e->fd, SIOCSIFLLADDR, &ifr)); +} +#else +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + errno = ENOSYS; + return (-1); +} +#endif diff --git a/libdnet-stripped/src/eth-dlpi.c b/libdnet-stripped/src/eth-dlpi.c new file mode 100644 index 0000000..dc7b8c9 --- /dev/null +++ b/libdnet-stripped/src/eth-dlpi.c @@ -0,0 +1,304 @@ +/* + * eth-dlpi.c + * + * Based on Neal Nuckolls' 1992 "How to Use DLPI" paper. + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: eth-dlpi.c 560 2005-02-10 16:48:36Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#ifdef HAVE_SYS_BUFMOD_H +#include <sys/bufmod.h> +#endif +#ifdef HAVE_SYS_DLPI_H +#include <sys/dlpi.h> +#elif defined(HAVE_SYS_DLPIHDR_H) +#include <sys/dlpihdr.h> +#endif +#ifdef HAVE_SYS_DLPI_EXT_H +#include <sys/dlpi_ext.h> +#endif +#include <sys/stream.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stropts.h> +#include <unistd.h> + +#include "dnet.h" + +#ifndef INFTIM +#define INFTIM -1 +#endif + +struct eth_handle { + int fd; + int sap_len; +}; + +static int +dlpi_msg(int fd, union DL_primitives *dlp, int rlen, int flags, + int ack, int alen, int size) +{ + struct strbuf ctl; + + ctl.maxlen = 0; + ctl.len = rlen; + ctl.buf = (caddr_t)dlp; + + if (putmsg(fd, &ctl, NULL, flags) < 0) + return (-1); + + ctl.maxlen = size; + ctl.len = 0; + + flags = 0; + + if (getmsg(fd, &ctl, NULL, &flags) < 0) + return (-1); + + if (dlp->dl_primitive != ack || ctl.len < alen) + return (-1); + + return (0); +} + +#if defined(DLIOCRAW) || defined(HAVE_SYS_DLPIHDR_H) +static int +strioctl(int fd, int cmd, int len, char *dp) +{ + struct strioctl str; + + str.ic_cmd = cmd; + str.ic_timout = INFTIM; + str.ic_len = len; + str.ic_dp = dp; + + if (ioctl(fd, I_STR, &str) < 0) + return (-1); + + return (str.ic_len); +} +#endif + +#ifdef HAVE_SYS_DLPIHDR_H +/* XXX - OSF1 is nuts */ +#define ND_GET ('N' << 8 + 0) + +static int +eth_match_ppa(eth_t *e, const char *device) +{ + char *p, dev[16], buf[256]; + int len, ppa; + + strlcpy(buf, "dl_ifnames", sizeof(buf)); + + if ((len = strioctl(e->fd, ND_GET, sizeof(buf), buf)) < 0) + return (-1); + + for (p = buf; p < buf + len; p += strlen(p) + 1) { + ppa = -1; + if (sscanf(p, "%s (PPA %d)\n", dev, &ppa) != 2) + break; + if (strcmp(dev, device) == 0) + break; + } + return (ppa); +} +#else +static char * +dev_find_ppa(char *dev) +{ + char *p; + + p = dev + strlen(dev); + while (p > dev && strchr("0123456789", *(p - 1)) != NULL) + p--; + if (*p == '\0') + return NULL; + + return p; +} +#endif + +eth_t * +eth_open(const char *device) +{ + union DL_primitives *dlp; + uint32_t buf[8192]; + char *p, dev[16]; + eth_t *e; + int ppa; + + if ((e = calloc(1, sizeof(*e))) == NULL) + return (NULL); + +#ifdef HAVE_SYS_DLPIHDR_H + if ((e->fd = open("/dev/streams/dlb", O_RDWR)) < 0) + return (eth_close(e)); + + if ((ppa = eth_match_ppa(e, device)) < 0) { + errno = ESRCH; + return (eth_close(e)); + } +#else + e->fd = -1; + snprintf(dev, sizeof(dev), "/dev/%s", device); + if ((p = dev_find_ppa(dev)) == NULL) { + errno = EINVAL; + return (eth_close(e)); + } + ppa = atoi(p); + *p = '\0'; + + if ((e->fd = open(dev, O_RDWR)) < 0) { + snprintf(dev, sizeof(dev), "/dev/%s", device); + if ((e->fd = open(dev, O_RDWR)) < 0) { + snprintf(dev, sizeof(dev), "/dev/net/%s", device); + if ((e->fd = open(dev, O_RDWR)) < 0) + return (eth_close(e)); + } + } +#endif + dlp = (union DL_primitives *)buf; + dlp->info_req.dl_primitive = DL_INFO_REQ; + + if (dlpi_msg(e->fd, dlp, DL_INFO_REQ_SIZE, RS_HIPRI, + DL_INFO_ACK, DL_INFO_ACK_SIZE, sizeof(buf)) < 0) + return (eth_close(e)); + + e->sap_len = dlp->info_ack.dl_sap_length; + + if (dlp->info_ack.dl_provider_style == DL_STYLE2) { + dlp->attach_req.dl_primitive = DL_ATTACH_REQ; + dlp->attach_req.dl_ppa = ppa; + + if (dlpi_msg(e->fd, dlp, DL_ATTACH_REQ_SIZE, 0, + DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf)) < 0) + return (eth_close(e)); + } + memset(&dlp->bind_req, 0, DL_BIND_REQ_SIZE); + dlp->bind_req.dl_primitive = DL_BIND_REQ; +#ifdef DL_HP_RAWDLS + dlp->bind_req.dl_sap = 24; /* from HP-UX DLPI programmers guide */ + dlp->bind_req.dl_service_mode = DL_HP_RAWDLS; +#else + dlp->bind_req.dl_sap = DL_ETHER; + dlp->bind_req.dl_service_mode = DL_CLDLS; +#endif + if (dlpi_msg(e->fd, dlp, DL_BIND_REQ_SIZE, 0, + DL_BIND_ACK, DL_BIND_ACK_SIZE, sizeof(buf)) < 0) + return (eth_close(e)); +#ifdef DLIOCRAW + if (strioctl(e->fd, DLIOCRAW, 0, NULL) < 0) + return (eth_close(e)); +#endif + return (e); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ +#if defined(DLIOCRAW) + return (write(e->fd, buf, len)); +#else + union DL_primitives *dlp; + struct strbuf ctl, data; + struct eth_hdr *eth; + uint32_t ctlbuf[8192]; + u_char sap[4] = { 0, 0, 0, 0 }; + int dlen; + + dlp = (union DL_primitives *)ctlbuf; +#ifdef DL_HP_RAWDATA_REQ + dlp->dl_primitive = DL_HP_RAWDATA_REQ; + dlen = DL_HP_RAWDATA_REQ_SIZE; +#else + dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ; + dlp->unitdata_req.dl_dest_addr_length = ETH_ADDR_LEN; + dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE; + dlp->unitdata_req.dl_priority.dl_min = + dlp->unitdata_req.dl_priority.dl_max = 0; + dlen = DL_UNITDATA_REQ_SIZE; +#endif + eth = (struct eth_hdr *)buf; + *(uint16_t *)sap = ntohs(eth->eth_type); + + /* XXX - DLSAP setup logic from ISC DHCP */ + ctl.maxlen = 0; + ctl.len = dlen + ETH_ADDR_LEN + abs(e->sap_len); + ctl.buf = (char *)ctlbuf; + + if (e->sap_len >= 0) { + memcpy(ctlbuf + dlen, sap, e->sap_len); + memcpy(ctlbuf + dlen + e->sap_len, + eth->eth_dst.data, ETH_ADDR_LEN); + } else { + memcpy(ctlbuf + dlen, eth->eth_dst.data, ETH_ADDR_LEN); + memcpy(ctlbuf + dlen + ETH_ADDR_LEN, sap, abs(e->sap_len)); + } + data.maxlen = 0; + data.len = len; + data.buf = (char *)buf; + + if (putmsg(e->fd, &ctl, &data, 0) < 0) + return (-1); + + return (len); +#endif +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + free(e); + } + return (NULL); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + union DL_primitives *dlp; + u_char buf[2048]; + + dlp = (union DL_primitives *)buf; + dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ; + dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR; + + if (dlpi_msg(e->fd, dlp, DL_PHYS_ADDR_REQ_SIZE, 0, + DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, sizeof(buf)) < 0) + return (-1); + + memcpy(ea, buf + dlp->physaddr_ack.dl_addr_offset, sizeof(*ea)); + + return (0); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + union DL_primitives *dlp; + u_char buf[2048]; + + dlp = (union DL_primitives *)buf; + dlp->set_physaddr_req.dl_primitive = DL_SET_PHYS_ADDR_REQ; + dlp->set_physaddr_req.dl_addr_length = ETH_ADDR_LEN; + dlp->set_physaddr_req.dl_addr_offset = DL_SET_PHYS_ADDR_REQ_SIZE; + + memcpy(buf + DL_SET_PHYS_ADDR_REQ_SIZE, ea, sizeof(*ea)); + + return (dlpi_msg(e->fd, dlp, DL_SET_PHYS_ADDR_REQ_SIZE + ETH_ADDR_LEN, + 0, DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf))); +} diff --git a/libdnet-stripped/src/eth-linux.c b/libdnet-stripped/src/eth-linux.c new file mode 100644 index 0000000..9b10840 --- /dev/null +++ b/libdnet-stripped/src/eth-linux.c @@ -0,0 +1,118 @@ +/* + * eth-linux.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth-linux.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <features.h> +#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1 +#include <netpacket/packet.h> +#include <net/ethernet.h> +#else +#include <asm/types.h> +#include <linux/if_packet.h> +#include <linux/if_ether.h> +#endif /* __GLIBC__ */ +#include <netinet/in.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct eth_handle { + int fd; + struct ifreq ifr; + struct sockaddr_ll sll; +}; + +eth_t * +eth_open(const char *device) +{ + eth_t *e; + int n; + + if ((e = calloc(1, sizeof(*e))) != NULL) { + if ((e->fd = socket(PF_PACKET, SOCK_RAW, + htons(ETH_P_ALL))) < 0) + return (eth_close(e)); +#ifdef SO_BROADCAST + n = 1; + if (setsockopt(e->fd, SOL_SOCKET, SO_BROADCAST, &n, + sizeof(n)) < 0) + return (eth_close(e)); +#endif + strlcpy(e->ifr.ifr_name, device, sizeof(e->ifr.ifr_name)); + + if (ioctl(e->fd, SIOCGIFINDEX, &e->ifr) < 0) + return (eth_close(e)); + + e->sll.sll_family = AF_PACKET; + e->sll.sll_ifindex = e->ifr.ifr_ifindex; + } + return (e); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + struct eth_hdr *eth = (struct eth_hdr *)buf; + + e->sll.sll_protocol = eth->eth_type; + + return (sendto(e->fd, buf, len, 0, (struct sockaddr *)&e->sll, + sizeof(e->sll))); +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + free(e); + } + return (NULL); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + struct addr ha; + + if (ioctl(e->fd, SIOCGIFHWADDR, &e->ifr) < 0) + return (-1); + + if (addr_ston(&e->ifr.ifr_hwaddr, &ha) < 0) + return (-1); + + memcpy(ea, &ha.addr_eth, sizeof(*ea)); + return (0); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + struct addr ha; + + ha.addr_type = ADDR_TYPE_ETH; + ha.addr_bits = ETH_ADDR_BITS; + memcpy(&ha.addr_eth, ea, ETH_ADDR_LEN); + + addr_ntos(&ha, &e->ifr.ifr_hwaddr); + + return (ioctl(e->fd, SIOCSIFHWADDR, &e->ifr)); +} diff --git a/libdnet-stripped/src/eth-ndd.c b/libdnet-stripped/src/eth-ndd.c new file mode 100644 index 0000000..7ac196c --- /dev/null +++ b/libdnet-stripped/src/eth-ndd.c @@ -0,0 +1,117 @@ +/* + * eth-ndd.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: eth-ndd.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ndd_var.h> +#include <sys/kinfo.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct eth_handle { + char device[16]; + int fd; +}; + +eth_t * +eth_open(const char *device) +{ + struct sockaddr_ndd_8022 sa; + eth_t *e; + + if ((e = calloc(1, sizeof(*e))) == NULL) + return (NULL); + + if ((e->fd = socket(AF_NDD, SOCK_DGRAM, NDD_PROT_ETHER)) < 0) + return (eth_close(e)); + + sa.sndd_8022_family = AF_NDD; + sa.sndd_8022_len = sizeof(sa); + sa.sndd_8022_filtertype = NS_ETHERTYPE; + sa.sndd_8022_ethertype = 0; + sa.sndd_8022_filterlen = sizeof(struct ns_8022); + strlcpy(sa.sndd_8022_nddname, device, sizeof(sa.sndd_8022_nddname)); + + if (bind(e->fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) + return (eth_close(e)); + + if (connect(e->fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) + return (eth_close(e)); + + /* XXX - SO_BROADCAST needed? */ + + return (e); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + return (write(e->fd, buf, len)); +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + free(e); + } + return (NULL); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + struct kinfo_ndd *nddp; + int size; + void *end; + + if ((size = getkerninfo(KINFO_NDD, 0, 0, 0)) == 0) { + errno = ENOENT; + return (-1); + } else if (size < 0) + return (-1); + + if ((nddp = malloc(size)) == NULL) + return (-1); + + if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) { + free(nddp); + return (-1); + } + for (end = (void *)nddp + size; (void *)nddp < end; nddp++) { + if (strcmp(nddp->ndd_alias, e->device) == 0 || + strcmp(nddp->ndd_name, e->device) == 0) { + memcpy(ea, nddp->ndd_addr, sizeof(*ea)); + } + } + free(nddp); + + if ((void *)nddp >= end) { + errno = ESRCH; + return (-1); + } + return (0); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + errno = ENOSYS; + return (-1); +} diff --git a/libdnet-stripped/src/eth-none.c b/libdnet-stripped/src/eth-none.c new file mode 100644 index 0000000..1ad0fef --- /dev/null +++ b/libdnet-stripped/src/eth-none.c @@ -0,0 +1,51 @@ +/* + * eth-none.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth-none.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +eth_t * +eth_open(const char *device) +{ + errno = ENOSYS; + return (NULL); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + errno = ENOSYS; + return (-1); +} + +eth_t * +eth_close(eth_t *e) +{ + return (NULL); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + errno = ENOSYS; + return (-1); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + errno = ENOSYS; + return (-1); +} diff --git a/libdnet-stripped/src/eth-pfilt.c b/libdnet-stripped/src/eth-pfilt.c new file mode 100644 index 0000000..aec0e12 --- /dev/null +++ b/libdnet-stripped/src/eth-pfilt.c @@ -0,0 +1,87 @@ +/* + * eth-pfilt.c + * + * XXX - requires 'cd dev && ./MAKEDEV pfilt' if not already configured... + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: eth-pfilt.c 563 2005-02-10 17:06:36Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/pfilt.h> + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct eth_handle { + int fd; + int sock; + char device[16]; +}; + +eth_t * +eth_open(const char *device) +{ + struct eth_handle *e; + int fd; + + if ((e = calloc(1, sizeof(*e))) != NULL) { + strlcpy(e->device, device, sizeof(e->device)); + if ((e->fd = pfopen(e->device, O_WRONLY)) < 0 || + (e->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + e = eth_close(e); + } + return (e); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + struct ifdevea ifd; + + strlcpy(ifd.ifr_name, e->device, sizeof(ifd.ifr_name)); + if (ioctl(e->sock, SIOCRPHYSADDR, &ifd) < 0) + return (-1); + memcpy(ea, ifd.current_pa, ETH_ADDR_LEN); + return (0); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + struct ifdevea ifd; + + strlcpy(ifd.ifr_name, e->device, sizeof(ifd.ifr_name)); + memcpy(ifd.current_pa, ea, ETH_ADDR_LEN); + return (ioctl(e->sock, SIOCSPHYSADDR, &ifd)); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + return (write(e->fd, buf, len)); +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + if (e->sock >= 0) + close(e->sock); + free(e); + } + return (NULL); +} diff --git a/libdnet-stripped/src/eth-snoop.c b/libdnet-stripped/src/eth-snoop.c new file mode 100644 index 0000000..a0147b8 --- /dev/null +++ b/libdnet-stripped/src/eth-snoop.c @@ -0,0 +1,109 @@ +/* + * eth-snoop.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth-snoop.c 548 2005-01-30 06:01:57Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/raw.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +struct eth_handle { + int fd; + struct ifreq ifr; +}; + +eth_t * +eth_open(const char *device) +{ + struct sockaddr_raw sr; + eth_t *e; + int n; + + if ((e = calloc(1, sizeof(*e))) == NULL) + return (NULL); + + if ((e->fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP)) < 0) + return (eth_close(e)); + + memset(&sr, 0, sizeof(sr)); + sr.sr_family = AF_RAW; + strlcpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); + + if (bind(e->fd, (struct sockaddr *)&sr, sizeof(sr)) < 0) + return (eth_close(e)); + + n = 60000; + if (setsockopt(e->fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) < 0) + return (eth_close(e)); + + strlcpy(e->ifr.ifr_name, device, sizeof(e->ifr.ifr_name)); + + return (e); +} + +int +eth_get(eth_t *e, eth_addr_t *ea) +{ + struct addr ha; + + if (ioctl(e->fd, SIOCGIFADDR, &e->ifr) < 0) + return (-1); + + if (addr_ston(&e->ifr.ifr_addr, &ha) < 0) + return (-1); + + if (ha.addr_type != ADDR_TYPE_ETH) { + errno = EINVAL; + return (-1); + } + memcpy(ea, &ha.addr_eth, sizeof(*ea)); + + return (0); +} + +int +eth_set(eth_t *e, const eth_addr_t *ea) +{ + struct addr ha; + + ha.addr_type = ADDR_TYPE_ETH; + ha.addr_bits = ETH_ADDR_BITS; + memcpy(&ha.addr_eth, ea, ETH_ADDR_LEN); + + if (addr_ntos(&ha, &e->ifr.ifr_addr) < 0) + return (-1); + + return (ioctl(e->fd, SIOCSIFADDR, &e->ifr)); +} + +ssize_t +eth_send(eth_t *e, const void *buf, size_t len) +{ + return (write(e->fd, buf, len)); +} + +eth_t * +eth_close(eth_t *e) +{ + if (e != NULL) { + if (e->fd >= 0) + close(e->fd); + free(e); + } + return (NULL); +} diff --git a/libdnet-stripped/src/eth-win32.c b/libdnet-stripped/src/eth-win32.c new file mode 100644 index 0000000..fc6aed1 --- /dev/null +++ b/libdnet-stripped/src/eth-win32.c @@ -0,0 +1,163 @@ +/* + * eth-win32.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth-win32.c 613 2005-09-26 02:46:57Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +/* XXX - VC++ 6.0 bogosity */ +#define sockaddr_storage sockaddr +#undef sockaddr_storage + +#include <errno.h> +#include <stdlib.h> + +#include "dnet.h" +#include <winsock2.h> +#include "pcap.h" +#include <Packet32.h> +#include <Ntddndis.h> + +/* From Npcap's Loopback.h */ +/* + * * Structure of a DLT_NULL header. + * */ +typedef struct _DLT_NULL_HEADER +{ + UINT null_type; +} DLT_NULL_HEADER, *PDLT_NULL_HEADER; + +/* + * * The length of the combined header. + * */ +#define DLT_NULL_HDR_LEN sizeof(DLT_NULL_HEADER) + +/* + * * Types in a DLT_NULL (Loopback) header. + * */ +#define DLTNULLTYPE_IP 0x00000002 /* IP protocol */ +#define DLTNULLTYPE_IPV6 0x00000018 /* IPv6 */ +/* END Loopback.h */ + +struct eth_handle { + LPADAPTER lpa; + LPPACKET pkt; + NetType type; +}; + +eth_t * +eth_open(const char *device) +{ + eth_t *eth; + char pcapdev[128]; + + if (eth_get_pcap_devname(device, pcapdev, sizeof(pcapdev)) != 0) + return (NULL); + + if ((eth = calloc(1, sizeof(*eth))) == NULL) + return (NULL); + eth->lpa = PacketOpenAdapter(pcapdev); + if (eth->lpa == NULL) { + eth_close(eth); + return (NULL); + } + PacketSetBuff(eth->lpa, 512000); + eth->pkt = PacketAllocatePacket(); + if (eth->pkt == NULL) { + eth_close(eth); + return NULL; + } + if (!PacketGetNetType(eth->lpa, ð->type)) { + eth_close(eth); + return NULL; + } + + return (eth); +} + +ssize_t +eth_send(eth_t *eth, const void *buf, size_t len) +{ + /* 14-byte Ethernet header, but DLT_NULL is a 4-byte header. Skip over the difference */ + DLT_NULL_HEADER *hdr = (DLT_NULL_HEADER *)((uint8_t *)buf + ETH_HDR_LEN - DLT_NULL_HDR_LEN); + if (eth->type.LinkType == NdisMediumNull) { + switch (ntohs(((struct eth_hdr *)buf)->eth_type)) { + case ETH_TYPE_IP: + hdr->null_type = DLTNULLTYPE_IP; + break; + case ETH_TYPE_IPV6: + hdr->null_type = DLTNULLTYPE_IPV6; + break; + default: + hdr->null_type = 0; + break; + } + PacketInitPacket(eth->pkt, (void *)((uint8_t *)buf + ETH_HDR_LEN - DLT_NULL_HDR_LEN), (UINT) (len - ETH_HDR_LEN + DLT_NULL_HDR_LEN)); + PacketSendPacket(eth->lpa, eth->pkt, TRUE); + } + else { + PacketInitPacket(eth->pkt, (void *)buf, (UINT) len); + PacketSendPacket(eth->lpa, eth->pkt, TRUE); + } + return (ssize_t)(len); +} + +eth_t * +eth_close(eth_t *eth) +{ + if (eth != NULL) { + if (eth->pkt != NULL) + PacketFreePacket(eth->pkt); + if (eth->lpa != NULL) + PacketCloseAdapter(eth->lpa); + free(eth); + } + return (NULL); +} + +int +eth_get(eth_t *eth, eth_addr_t *ea) +{ + PACKET_OID_DATA *data; + u_char buf[512]; + + data = (PACKET_OID_DATA *)buf; + data->Oid = OID_802_3_CURRENT_ADDRESS; + data->Length = ETH_ADDR_LEN; + + if (PacketRequest(eth->lpa, FALSE, data) == TRUE) { + memcpy(ea, data->Data, ETH_ADDR_LEN); + return (0); + } + return (-1); +} + +int +eth_set(eth_t *eth, const eth_addr_t *ea) +{ + PACKET_OID_DATA *data; + u_char buf[512]; + + data = (PACKET_OID_DATA *)buf; + data->Oid = OID_802_3_CURRENT_ADDRESS; + memcpy(data->Data, ea, ETH_ADDR_LEN); + data->Length = ETH_ADDR_LEN; + + if (PacketRequest(eth->lpa, TRUE, data) == TRUE) + return (0); + + return (-1); +} + +int +eth_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen) +{ + return intf_get_pcap_devname(intf_name, pcapdev, pcapdevlen); +} diff --git a/libdnet-stripped/src/fw-none.c b/libdnet-stripped/src/fw-none.c new file mode 100644 index 0000000..f2c84bf --- /dev/null +++ b/libdnet-stripped/src/fw-none.c @@ -0,0 +1,49 @@ +/* + * fw-none.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: fw-none.c 208 2002-01-20 21:23:28Z dugsong $ + */ + +#include "config.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +fw_t * +fw_open(void) +{ + errno = ENOSYS; + return (NULL); +} + +int +fw_add(fw_t *f, const struct fw_rule *rule) +{ + errno = ENOSYS; + return (-1); +} + +int +fw_delete(fw_t *f, const struct fw_rule *rule) +{ + errno = ENOSYS; + return (-1); +} + +int +fw_loop(fw_t *f, fw_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} + +fw_t * +fw_close(fw_t *f) +{ + return (NULL); +} diff --git a/libdnet-stripped/src/intf-win32.c b/libdnet-stripped/src/intf-win32.c new file mode 100644 index 0000000..245289f --- /dev/null +++ b/libdnet-stripped/src/intf-win32.c @@ -0,0 +1,621 @@ +/* + * intf-win32.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: intf-win32.c 632 2006-08-10 04:36:52Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <iphlpapi.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" +#include "pcap.h" +#include <Packet32.h> +#include <Ntddndis.h> + +int g_has_npcap_loopback = 0; +#define _DEVICE_PREFIX "\\Device\\" + +struct ifcombo { + struct { + DWORD ipv4; + DWORD ipv6; + } *idx; + int cnt; + int max; +}; + +/* XXX - ipifcons.h incomplete, use IANA ifTypes MIB */ +#define MIB_IF_TYPE_TUNNEL 131 +#define MIB_IF_TYPE_MAX MAX_IF_TYPE + +struct intf_handle { + struct ifcombo ifcombo[MIB_IF_TYPE_MAX]; + IP_ADAPTER_ADDRESSES *iftable; +}; + +static char * +_ifcombo_name(int type) +{ + char *name = NULL; + + switch (type) { + case IF_TYPE_ETHERNET_CSMACD: + case IF_TYPE_IEEE80211: + name = "eth"; + break; + case IF_TYPE_ISO88025_TOKENRING: + name = "tr"; + break; + case IF_TYPE_PPP: + name = "ppp"; + break; + case IF_TYPE_SOFTWARE_LOOPBACK: + name = "lo"; + break; + case IF_TYPE_TUNNEL: + name = "tun"; + break; + default: + name = "unk"; + break; + } + return (name); +} + +static int +_ifcombo_type(const char *device) +{ + int type = INTF_TYPE_OTHER; + + if (strncmp(device, "eth", 3) == 0) { + type = INTF_TYPE_ETH; + } else if (strncmp(device, "tr", 2) == 0) { + type = INTF_TYPE_TOKENRING; + } else if (strncmp(device, "ppp", 3) == 0) { + type = INTF_TYPE_PPP; + } else if (strncmp(device, "lo", 2) == 0) { + type = INTF_TYPE_LOOPBACK; + } else if (strncmp(device, "tun", 3) == 0) { + type = INTF_TYPE_TUN; + } + return (type); +} + +static void +_ifcombo_add(struct ifcombo *ifc, DWORD ipv4_idx, DWORD ipv6_idx) +{ + void* pmem = NULL; + if (ifc->cnt == ifc->max) { + if (ifc->idx) { + ifc->max *= 2; + pmem = realloc(ifc->idx, + sizeof(ifc->idx[0]) * ifc->max); + } else { + ifc->max = 8; + pmem = malloc(sizeof(ifc->idx[0]) * ifc->max); + } + if (!pmem) { + /* malloc or realloc failed. Restore state. + * TODO: notify caller. */ + ifc->max = ifc->cnt; + return; + } + ifc->idx = pmem; + } + ifc->idx[ifc->cnt].ipv4 = ipv4_idx; + ifc->idx[ifc->cnt].ipv6 = ipv6_idx; + ifc->cnt++; +} + +/* Map an MIB interface type into an internal interface type. The + internal types are never exposed to users of this library; they exist + only for the sake of ordering interface types within an intf_handle, + which has an array of ifcombo structures ordered by type. Entries in + an intf_handle must not be stored or accessed by a raw MIB type + number because they will not be able to be found by a device name + such as "net0" if the device name does not map exactly to the type. */ +static int +_if_type_canonicalize(int type) +{ + return _ifcombo_type(_ifcombo_name(type)); +} + +static void +_adapter_address_to_entry(intf_t *intf, IP_ADAPTER_ADDRESSES *a, + struct intf_entry *entry) +{ + struct addr *ap, *lap; + int i; + int type; + IP_ADAPTER_UNICAST_ADDRESS *addr; + + /* The total length of the entry may be passed inside entry. + Remember it and clear the entry. */ + u_int intf_len = entry->intf_len; + memset(entry, 0, sizeof(*entry)); + entry->intf_len = intf_len; + + type = _if_type_canonicalize(a->IfType); + for (i = 0; i < intf->ifcombo[type].cnt; i++) { + if (intf->ifcombo[type].idx[i].ipv4 == a->IfIndex && + intf->ifcombo[type].idx[i].ipv6 == a->Ipv6IfIndex) { + break; + } + } + /* XXX - type matches MIB-II ifType. */ + snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu", + _ifcombo_name(a->IfType), i); + entry->intf_type = (uint16_t)type; + + /* Get interface flags. */ + entry->intf_flags = 0; + if (a->OperStatus == IfOperStatusUp) + entry->intf_flags |= INTF_FLAG_UP; + if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) + entry->intf_flags |= INTF_FLAG_LOOPBACK; + else + entry->intf_flags |= INTF_FLAG_MULTICAST; + + /* Get interface MTU. */ + entry->intf_mtu = a->Mtu; + + /* Get hardware address. */ + if (a->PhysicalAddressLength == ETH_ADDR_LEN) { + entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; + entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; + memcpy(&entry->intf_link_addr.addr_eth, a->PhysicalAddress, + ETH_ADDR_LEN); + } + /* Get addresses. */ + ap = entry->intf_alias_addrs; + lap = ap + ((entry->intf_len - sizeof(*entry)) / + sizeof(entry->intf_alias_addrs[0])); + for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) { + IP_ADAPTER_PREFIX *prefix; + unsigned short bits; + + /* Find the netmask length. This is stored in a parallel list. + We just take the first one with a matching address family, + but that may not be right. Windows Vista and later has an + OnLinkPrefixLength member that is stored right with the + unicast address. */ + bits = 0; + if (addr->Length >= 48) { + /* "The size of the IP_ADAPTER_UNICAST_ADDRESS structure changed on + * Windows Vista and later. The Length member should be used to determine + * which version of the IP_ADAPTER_UNICAST_ADDRESS structure is being + * used." + * Empirically, 48 is the value on Windows 8.1, so should include the + * OnLinkPrefixLength member.*/ + bits = addr->OnLinkPrefixLength; + } + else { + for (prefix = a->FirstPrefix; prefix != NULL; prefix = prefix->Next) { + if (prefix->Address.lpSockaddr->sa_family == addr->Address.lpSockaddr->sa_family) { + bits = (unsigned short) prefix->PrefixLength; + break; + } + } + } + + if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) { + /* Set primary address if unset. */ + addr_ston(addr->Address.lpSockaddr, &entry->intf_addr); + entry->intf_addr.addr_bits = bits; + } else if (ap < lap) { + /* Set aliases. */ + addr_ston(addr->Address.lpSockaddr, ap); + ap->addr_bits = bits; + ap++; + entry->intf_alias_num++; + } + } + entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry); +} + +#define NPCAP_SERVICE_REGISTRY_KEY "SYSTEM\\CurrentControlSet\\Services\\npcap" + +/* The name of the Npcap loopback adapter is stored in the npcap service's + * Registry key in the LoopbackAdapter value. For legacy loopback support, this + * is a name like "NPF_{GUID}", but for newer Npcap the name is "NPF_Loopback" + */ +int intf_get_loopback_name(char *buffer, int buf_size) +{ + HKEY hKey; + DWORD type; + int size = buf_size; + int res = 0; + + memset(buffer, 0, buf_size); + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, NPCAP_SERVICE_REGISTRY_KEY "\\Parameters", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueExA(hKey, "LoopbackAdapter", 0, &type, (LPBYTE)buffer, &size) == ERROR_SUCCESS && type == REG_SZ) + { + res = 1; + } + else + { + res = 0; + } + + RegCloseKey(hKey); + } + else + { + res = 0; + } + + return res; +} + +static IP_ADAPTER_ADDRESSES* +_update_tables_for_npcap_loopback(IP_ADAPTER_ADDRESSES *p) +{ + IP_ADAPTER_ADDRESSES *a_prev = NULL; + IP_ADAPTER_ADDRESSES *a; + IP_ADAPTER_ADDRESSES *a_original_loopback_prev = NULL; + IP_ADAPTER_ADDRESSES *a_original_loopback = NULL; + IP_ADAPTER_ADDRESSES *a_npcap_loopback = NULL; + static char npcap_loopback_name[1024] = {0}; + + /* Don't bother hitting the registry every time. Not ideal for long-running + * processes, but works for Nmap. */ + if (npcap_loopback_name[0] == '\0') + g_has_npcap_loopback = intf_get_loopback_name(npcap_loopback_name, 1024); + else if (g_has_npcap_loopback == 0) + return p; + + if (!p) + return p; + + /* Loop through the addresses looking for the dummy loopback interface from Windows. */ + for (a = p; a != NULL; a = a->Next) { + if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { + /* Dummy loopback. Keep track of it. */ + a_original_loopback = a; + a_original_loopback_prev = a_prev; + } + else if (strcmp(a->AdapterName, npcap_loopback_name + strlen(_DEVICE_PREFIX) - 1) == 0) { + /* Legacy loopback adapter. The modern one doesn't show up in GetAdaptersAddresses. */ + a_npcap_loopback = a; + } + a_prev = a; + } + + /* If there's no loopback on this system, something's wrong. Windows is + * supposed to create this. */ + if (!a_original_loopback) + return p; + g_has_npcap_loopback = 1; + /* If we didn't find the legacy adapter, use the modern adapter name. */ + if (!a_npcap_loopback) { + /* Overwrite the name we got from the Registry, in case it's a broken legacy + * install, in which case we'll never find the legacy adapter anyway. */ + strlcpy(npcap_loopback_name, _DEVICE_PREFIX "NPF_Loopback", 1024); + /* Overwrite the AdapterName from the system's own loopback adapter with + * the NPF_Loopback name. This is what we use to open the adapter with + * Packet.dll later. */ + a_original_loopback->AdapterName = npcap_loopback_name + sizeof(_DEVICE_PREFIX) - 1; + return p; + } + else { + /* Legacy loopback adapter was found. Copy some key info from the system's + * loopback adapter. */ + a_npcap_loopback->IfType = a_original_loopback->IfType; + a_npcap_loopback->FirstUnicastAddress = a_original_loopback->FirstUnicastAddress; + a_npcap_loopback->FirstPrefix = a_original_loopback->FirstPrefix; + memset(a_npcap_loopback->PhysicalAddress, 0, ETH_ADDR_LEN); + /* Unlink the original loopback adapter from the list. We'll use Npcap's instead. */ + if (a_original_loopback_prev) { + a_original_loopback_prev->Next = a_original_loopback_prev->Next->Next; + return p; + } + else if (a_original_loopback == p) { + return a_original_loopback->Next; + } + else { + return p; + } + } +} + +static int +_refresh_tables(intf_t *intf) +{ + IP_ADAPTER_ADDRESSES *p; + DWORD ret; + ULONG len; + + p = NULL; + /* GetAdaptersAddresses is supposed to return ERROR_BUFFER_OVERFLOW and + * set len to the required size when len is too small. So normally we + * would call the function once with a small len, and then again with + * the longer len. But, on Windows 2003, apparently you only get + * ERROR_BUFFER_OVERFLOW the *first* time you call the function with a + * too-small len--the next time you get ERROR_INVALID_PARAMETER. So this + * function would fail the second and later times it is called. + * + * So, make the first call using a large len. On Windows 2003, this will + * work the first time as long as there are not too many adapters. (It + * will still fail with ERROR_INVALID_PARAMETER if there are too many + * adapters, but this will happen infrequently because of the large + * buffer.) Other systems that always return ERROR_BUFFER_OVERFLOW when + * appropriate will enlarge the buffer if the initial len is too short. */ + len = 16384; + do { + free(p); + p = malloc(len); + if (p == NULL) + return (-1); + ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, p, &len); + } while (ret == ERROR_BUFFER_OVERFLOW); + + if (ret != NO_ERROR) { + free(p); + return (-1); + } + p = _update_tables_for_npcap_loopback(p); + intf->iftable = p; + + /* + * Map "unfriendly" win32 interface indices to ours. + * XXX - like IP_ADAPTER_INFO ComboIndex + */ + for (p = intf->iftable; p != NULL; p = p->Next) { + int type; + type = _if_type_canonicalize(p->IfType); + if (type < MIB_IF_TYPE_MAX) + _ifcombo_add(&intf->ifcombo[type], p->IfIndex, p->Ipv6IfIndex); + else + return (-1); + } + return (0); +} + +static IP_ADAPTER_ADDRESSES * +_find_adapter_address(intf_t *intf, const char *device) +{ + IP_ADAPTER_ADDRESSES *a; + char *p = (char *)device; + int n, type = _ifcombo_type(device); + + while (isalpha((int) (unsigned char) *p)) p++; + n = atoi(p); + + for (a = intf->iftable; a != NULL; a = a->Next) { + if ( intf->ifcombo[type].idx != NULL && + intf->ifcombo[type].idx[n].ipv4 == a->IfIndex && + intf->ifcombo[type].idx[n].ipv6 == a->Ipv6IfIndex) { + return a; + } + } + + return NULL; +} + +static IP_ADAPTER_ADDRESSES * +_find_adapter_address_by_index(intf_t *intf, int af, unsigned int index) +{ + IP_ADAPTER_ADDRESSES *a; + + for (a = intf->iftable; a != NULL; a = a->Next) { + if (af == AF_INET && index == a->IfIndex) + return a; + if (af == AF_INET6 && index == a->Ipv6IfIndex) + return a; + } + + return NULL; +} + +intf_t * +intf_open(void) +{ + return (calloc(1, sizeof(intf_t))); +} + +int +intf_get(intf_t *intf, struct intf_entry *entry) +{ + IP_ADAPTER_ADDRESSES *a; + + if (_refresh_tables(intf) < 0) + return (-1); + + a = _find_adapter_address(intf, entry->intf_name); + if (a == NULL) + return (-1); + + _adapter_address_to_entry(intf, a, entry); + + return (0); +} + +/* Look up an interface from an index, such as a sockaddr_in6.sin6_scope_id. */ +int +intf_get_index(intf_t *intf, struct intf_entry *entry, int af, unsigned int index) +{ + IP_ADAPTER_ADDRESSES *a; + + if (_refresh_tables(intf) < 0) + return (-1); + + a = _find_adapter_address_by_index(intf, af, index); + if (a == NULL) + return (-1); + + _adapter_address_to_entry(intf, a, entry); + + return (0); +} + +int +intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src) +{ + IP_ADAPTER_ADDRESSES *a; + IP_ADAPTER_UNICAST_ADDRESS *addr; + + if (src->addr_type != ADDR_TYPE_IP) { + errno = EINVAL; + return (-1); + } + if (_refresh_tables(intf) < 0) + return (-1); + + for (a = intf->iftable; a != NULL; a = a->Next) { + for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) { + struct addr dnet_addr; + + addr_ston(addr->Address.lpSockaddr, &dnet_addr); + if (addr_cmp(&dnet_addr, src) == 0) { + _adapter_address_to_entry(intf, a, entry); + return (0); + } + } + } + errno = ENXIO; + return (-1); +} + +int +intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst) +{ + errno = ENOSYS; + SetLastError(ERROR_NOT_SUPPORTED); + return (-1); +} + +int +intf_set(intf_t *intf, const struct intf_entry *entry) +{ + /* + * XXX - could set interface up/down via SetIfEntry(), + * but what about the rest of the configuration? :-( + * {Add,Delete}IPAddress for 2000/XP only + */ + errno = ENOSYS; + SetLastError(ERROR_NOT_SUPPORTED); + return (-1); +} + +int +intf_loop(intf_t *intf, intf_handler callback, void *arg) +{ + IP_ADAPTER_ADDRESSES *a; + struct intf_entry *entry; + u_char ebuf[1024]; + int ret = 0; + + if (_refresh_tables(intf) < 0) + return (-1); + + entry = (struct intf_entry *)ebuf; + + for (a = intf->iftable; a != NULL; a = a->Next) { + entry->intf_len = sizeof(ebuf); + _adapter_address_to_entry(intf, a, entry); + if ((ret = (*callback)(entry, arg)) != 0) + break; + } + return (ret); +} + +intf_t * +intf_close(intf_t *intf) +{ + int i; + + if (intf != NULL) { + for (i = 0; i < MIB_IF_TYPE_MAX; i++) { + if (intf->ifcombo[i].idx) + free(intf->ifcombo[i].idx); + } + if (intf->iftable) + free(intf->iftable); + free(intf); + } + return (NULL); +} + +/* Converts a libdnet interface name to its pcap equivalent. The pcap name is + stored in pcapdev up to a length of pcapdevlen, including the terminating + '\0'. Returns -1 on error. */ +int +intf_get_pcap_devname_cached(const char *intf_name, char *pcapdev, int pcapdevlen, int refresh) +{ + IP_ADAPTER_ADDRESSES *a; + static pcap_if_t *pcapdevs = NULL; + pcap_if_t *pdev; + intf_t *intf; + char errbuf[PCAP_ERRBUF_SIZE]; + + if ((intf = intf_open()) == NULL) + return (-1); + if (_refresh_tables(intf) < 0) { + intf_close(intf); + return (-1); + } + a = _find_adapter_address(intf, intf_name); + + if (a == NULL) { + intf_close(intf); + return (-1); + } + + if (refresh) { + pcap_freealldevs(pcapdevs); + pcapdevs = NULL; + } + + if (pcapdevs == NULL) { + if (pcap_findalldevs(&pcapdevs, errbuf) == -1) { + intf_close(intf); + return (-1); + } + } + + /* Loop through all the pcap devices until we find a match. */ + for (pdev = pcapdevs; pdev != NULL; pdev = pdev->next) { + char *name; + + if (pdev->name == NULL || strlen(pdev->name) < sizeof(_DEVICE_PREFIX)) + continue; + /* "\\Device\\NPF_{GUID}" + * "\\Device\\NPF_Loopback" + * Find the '{'after device prefix. + */ + name = strchr(pdev->name + sizeof(_DEVICE_PREFIX) - 1, '{'); + if (name == NULL) { + /* If no GUID, just match the whole device name */ + name = pdev->name + sizeof(_DEVICE_PREFIX) - 1; + } + if (strcmp(name, a->AdapterName) == 0) + break; + } + if (pdev != NULL) + strlcpy(pcapdev, pdev->name, pcapdevlen); + intf_close(intf); + if (pdev == NULL) + return -1; + else + return 0; +} +int +intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen) +{ + return intf_get_pcap_devname_cached(intf_name, pcapdev, pcapdevlen, 0); +} diff --git a/libdnet-stripped/src/intf.c b/libdnet-stripped/src/intf.c new file mode 100644 index 0000000..d4faaeb --- /dev/null +++ b/libdnet-stripped/src/intf.c @@ -0,0 +1,1091 @@ +/* + * intf.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: intf.c 616 2006-01-09 07:09:49Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SOCKIO_H +# include <sys/sockio.h> +#endif +/* XXX - AIX */ +#ifdef HAVE_GETKERNINFO +#include <sys/ndd_var.h> +#include <sys/kinfo.h> +#endif +#ifndef IP_MULTICAST +# define IP_MULTICAST +#endif +#include <net/if.h> +#ifdef HAVE_NET_IF_VAR_H +# include <net/if_var.h> +#endif +#undef IP_MULTICAST +/* XXX - IPv6 ioctls */ +#ifdef HAVE_NETINET_IN_VAR_H +# include <netinet/in.h> +# include <netinet/in_var.h> +#endif +#ifdef HAVE_NETINET_IN6_VAR_H +# include <sys/protosw.h> +# include <netinet/in6_var.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +/* XXX - Tru64 */ +#if defined(SIOCRIPMTU) && defined(SIOCSIPMTU) +# define SIOCGIFMTU SIOCRIPMTU +# define SIOCSIFMTU SIOCSIPMTU +#endif + +/* XXX - HP-UX */ +#if defined(SIOCADDIFADDR) && defined(SIOCDELIFADDR) +# define SIOCAIFADDR SIOCADDIFADDR +# define SIOCDIFADDR SIOCDELIFADDR +#endif + +/* XXX - HP-UX, Solaris */ +#if !defined(ifr_mtu) && defined(ifr_metric) +# define ifr_mtu ifr_metric +#endif + +#ifdef HAVE_SOCKADDR_SA_LEN +# define max(a, b) ((a) > (b) ? (a) : (b)) +# define NEXTIFR(i) ((struct ifreq *) \ + max((u_char *)i + sizeof(struct ifreq), \ + (u_char *)&i->ifr_addr + i->ifr_addr.sa_len)) +#else +# define NEXTIFR(i) (i + 1) +#endif + +#define NEXTLIFR(i) (i + 1) + +/* XXX - superset of ifreq, for portable SIOC{A,D}IFADDR */ +struct dnet_ifaliasreq { + char ifra_name[IFNAMSIZ]; + union { + struct sockaddr ifrau_addr; + int ifrau_align; + } ifra_ifrau; +#ifndef ifra_addr +#define ifra_addr ifra_ifrau.ifrau_addr +#endif + struct sockaddr ifra_brdaddr; + struct sockaddr ifra_mask; + int ifra_cookie; /* XXX - IRIX!@#$ */ +}; + +struct intf_handle { + int fd; + int fd6; + struct ifconf ifc; +#ifdef SIOCGLIFCONF + struct lifconf lifc; +#endif + u_char ifcbuf[4192]; +}; + +static int +intf_flags_to_iff(u_short flags, int iff) +{ + if (flags & INTF_FLAG_UP) + iff |= IFF_UP; + else + iff &= ~IFF_UP; + if (flags & INTF_FLAG_NOARP) + iff |= IFF_NOARP; + else + iff &= ~IFF_NOARP; + + return (iff); +} + +static u_int +intf_iff_to_flags(uint64_t iff) +{ + u_int n = 0; + + if (iff & IFF_UP) + n |= INTF_FLAG_UP; + if (iff & IFF_LOOPBACK) + n |= INTF_FLAG_LOOPBACK; + if (iff & IFF_POINTOPOINT) + n |= INTF_FLAG_POINTOPOINT; + if (iff & IFF_NOARP) + n |= INTF_FLAG_NOARP; + if (iff & IFF_BROADCAST) + n |= INTF_FLAG_BROADCAST; + if (iff & IFF_MULTICAST) + n |= INTF_FLAG_MULTICAST; +#ifdef IFF_IPMP + /* Unset the BROADCAST and MULTICAST flags from Solaris IPMP interfaces, + * otherwise _intf_set_type will think they are INTF_TYPE_ETH. */ + if (iff & IFF_IPMP) + n &= ~(INTF_FLAG_BROADCAST | INTF_FLAG_MULTICAST); +#endif + + return (n); +} + +intf_t * +intf_open(void) +{ + intf_t *intf; + int one = 1; + + if ((intf = calloc(1, sizeof(*intf))) != NULL) { + intf->fd = intf->fd6 = -1; + + if ((intf->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (intf_close(intf)); + + setsockopt(intf->fd, SOL_SOCKET, SO_BROADCAST, + (const char *) &one, sizeof(one)); + +#if defined(SIOCGLIFCONF) || defined(SIOCGIFNETMASK_IN6) || defined(SIOCGIFNETMASK6) + if ((intf->fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { +# ifdef EPROTONOSUPPORT + if (errno != EPROTONOSUPPORT) +# endif + return (intf_close(intf)); + } +#endif + } + return (intf); +} + +static int +_intf_delete_addrs(intf_t *intf, struct intf_entry *entry) +{ +#if defined(SIOCDIFADDR) + struct dnet_ifaliasreq ifra; + + memset(&ifra, 0, sizeof(ifra)); + strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); + if (entry->intf_addr.addr_type == ADDR_TYPE_IP) { + addr_ntos(&entry->intf_addr, &ifra.ifra_addr); + ioctl(intf->fd, SIOCDIFADDR, &ifra); + } + if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) { + addr_ntos(&entry->intf_dst_addr, &ifra.ifra_addr); + ioctl(intf->fd, SIOCDIFADDR, &ifra); + } +#elif defined(SIOCLIFREMOVEIF) + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); + /* XXX - overloading Solaris lifreq with ifreq */ + ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr); +#endif + return (0); +} + +static int +_intf_delete_aliases(intf_t *intf, struct intf_entry *entry) +{ + int i; +#if defined(SIOCDIFADDR) && !defined(__linux__) /* XXX - see Linux below */ + struct dnet_ifaliasreq ifra; + + memset(&ifra, 0, sizeof(ifra)); + strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); + + for (i = 0; i < (int)entry->intf_alias_num; i++) { + addr_ntos(&entry->intf_alias_addrs[i], &ifra.ifra_addr); + ioctl(intf->fd, SIOCDIFADDR, &ifra); + } +#else + struct ifreq ifr; + + for (i = 0; i < entry->intf_alias_num; i++) { + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d", + entry->intf_name, i + 1); +# ifdef SIOCLIFREMOVEIF + /* XXX - overloading Solaris lifreq with ifreq */ + ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr); +# else + /* XXX - only need to set interface down on Linux */ + ifr.ifr_flags = 0; + ioctl(intf->fd, SIOCSIFFLAGS, &ifr); +# endif + } +#endif + return (0); +} + +static int +_intf_add_aliases(intf_t *intf, const struct intf_entry *entry) +{ + int i; +#ifdef SIOCAIFADDR + struct dnet_ifaliasreq ifra; + struct addr bcast; + + memset(&ifra, 0, sizeof(ifra)); + strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); + + for (i = 0; i < (int)entry->intf_alias_num; i++) { + if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP) + continue; + + if (addr_ntos(&entry->intf_alias_addrs[i], + &ifra.ifra_addr) < 0) + return (-1); + addr_bcast(&entry->intf_alias_addrs[i], &bcast); + addr_ntos(&bcast, &ifra.ifra_brdaddr); + addr_btos(entry->intf_alias_addrs[i].addr_bits, + &ifra.ifra_mask); + + if (ioctl(intf->fd, SIOCAIFADDR, &ifra) < 0) + return (-1); + } +#else + struct ifreq ifr; + int n = 1; + + for (i = 0; i < entry->intf_alias_num; i++) { + if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP) + continue; + + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d", + entry->intf_name, n++); +# ifdef SIOCLIFADDIF + if (ioctl(intf->fd, SIOCLIFADDIF, &ifr) < 0) + return (-1); +# endif + if (addr_ntos(&entry->intf_alias_addrs[i], &ifr.ifr_addr) < 0) + return (-1); + if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0) + return (-1); + } + strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); +#endif + return (0); +} + +int +intf_set(intf_t *intf, const struct intf_entry *entry) +{ + struct ifreq ifr; + struct intf_entry *orig; + struct addr bcast; + u_char buf[BUFSIZ]; + + orig = (struct intf_entry *)buf; + orig->intf_len = sizeof(buf); + strcpy(orig->intf_name, entry->intf_name); + + if (intf_get(intf, orig) < 0) + return (-1); + + /* Delete any existing aliases. */ + if (_intf_delete_aliases(intf, orig) < 0) + return (-1); + + /* Delete any existing addrs. */ + if (_intf_delete_addrs(intf, orig) < 0) + return (-1); + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); + + /* Set interface MTU. */ + if (entry->intf_mtu != 0) { + ifr.ifr_mtu = entry->intf_mtu; +#ifdef SIOCSIFMTU + if (ioctl(intf->fd, SIOCSIFMTU, &ifr) < 0) +#endif + return (-1); + } + /* Set interface address. */ + if (entry->intf_addr.addr_type == ADDR_TYPE_IP) { +#if defined(BSD) && !defined(__OPENBSD__) + /* XXX - why must this happen before SIOCSIFADDR? */ + if (addr_btos(entry->intf_addr.addr_bits, + &ifr.ifr_addr) == 0) { + if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) + return (-1); + } +#endif + if (addr_ntos(&entry->intf_addr, &ifr.ifr_addr) < 0) + return (-1); + if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0 && errno != EEXIST) + return (-1); + + if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0 +#ifdef __linux__ + && entry->intf_addr.addr_ip != 0 +#endif + ) { + if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0) + return (-1); + } + if (addr_bcast(&entry->intf_addr, &bcast) == 0) { + if (addr_ntos(&bcast, &ifr.ifr_broadaddr) == 0) { + /* XXX - ignore error from non-broadcast ifs */ + ioctl(intf->fd, SIOCSIFBRDADDR, &ifr); + } + } + } + /* Set link-level address. */ + if (entry->intf_link_addr.addr_type == ADDR_TYPE_ETH && + addr_cmp(&entry->intf_link_addr, &orig->intf_link_addr) != 0) { +#if defined(SIOCSIFHWADDR) + if (addr_ntos(&entry->intf_link_addr, &ifr.ifr_hwaddr) < 0) + return (-1); + if (ioctl(intf->fd, SIOCSIFHWADDR, &ifr) < 0) + return (-1); +#elif defined (SIOCSIFLLADDR) + memcpy(ifr.ifr_addr.sa_data, &entry->intf_link_addr.addr_eth, + ETH_ADDR_LEN); + ifr.ifr_addr.sa_len = ETH_ADDR_LEN; + if (ioctl(intf->fd, SIOCSIFLLADDR, &ifr) < 0) + return (-1); +#else + eth_t *eth; + + if ((eth = eth_open(entry->intf_name)) == NULL) + return (-1); + if (eth_set(eth, &entry->intf_link_addr.addr_eth) < 0) { + eth_close(eth); + return (-1); + } + eth_close(eth); +#endif + } + /* Set point-to-point destination. */ + if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) { + if (addr_ntos(&entry->intf_dst_addr, &ifr.ifr_dstaddr) < 0) + return (-1); + if (ioctl(intf->fd, SIOCSIFDSTADDR, &ifr) < 0 && + errno != EEXIST) + return (-1); + } + /* Add aliases. */ + if (_intf_add_aliases(intf, entry) < 0) + return (-1); + + /* Set interface flags. */ + if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) + return (-1); + + ifr.ifr_flags = intf_flags_to_iff(entry->intf_flags, ifr.ifr_flags); + + if (ioctl(intf->fd, SIOCSIFFLAGS, &ifr) < 0) + return (-1); + + return (0); +} + +/* XXX - this is total crap. how to do this without walking ifnet? */ +static void +_intf_set_type(struct intf_entry *entry) +{ + if ((entry->intf_flags & INTF_FLAG_LOOPBACK) != 0) + entry->intf_type = INTF_TYPE_LOOPBACK; + else if ((entry->intf_flags & INTF_FLAG_BROADCAST) != 0) + entry->intf_type = INTF_TYPE_ETH; + else if ((entry->intf_flags & INTF_FLAG_POINTOPOINT) != 0) + entry->intf_type = INTF_TYPE_TUN; + else + entry->intf_type = INTF_TYPE_OTHER; +} + +#ifdef SIOCGLIFCONF +int +_intf_get_noalias(intf_t *intf, struct intf_entry *entry) +{ + struct lifreq lifr; + int fd; + + /* Get interface index. */ + entry->intf_index = if_nametoindex(entry->intf_name); + if (entry->intf_index == 0) + return (-1); + + strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name)); + + /* Get interface flags. Here he also check whether we need to use fd or + * fd6 in the rest of the function. Using the wrong address family in + * the ioctls gives ENXIO on Solaris. */ + if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) >= 0) + fd = intf->fd; + else if (intf->fd6 != -1 && ioctl(intf->fd6, SIOCGLIFFLAGS, &lifr) >= 0) + fd = intf->fd6; + else + return (-1); + + entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags); + _intf_set_type(entry); + + /* Get interface MTU. */ +#ifdef SIOCGLIFMTU + if (ioctl(fd, SIOCGLIFMTU, &lifr) < 0) +#endif + return (-1); + entry->intf_mtu = lifr.lifr_mtu; + + entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = + entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; + + /* Get primary interface address. */ + if (ioctl(fd, SIOCGLIFADDR, &lifr) == 0) { + addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr); + if (ioctl(fd, SIOCGLIFNETMASK, &lifr) < 0) + return (-1); + addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits); + } + /* Get other addresses. */ + if (entry->intf_type == INTF_TYPE_TUN) { + if (ioctl(fd, SIOCGLIFDSTADDR, &lifr) == 0) { + if (addr_ston((struct sockaddr *)&lifr.lifr_addr, + &entry->intf_dst_addr) < 0) + return (-1); + } + } else if (entry->intf_type == INTF_TYPE_ETH) { + eth_t *eth; + + if ((eth = eth_open(entry->intf_name)) != NULL) { + if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { + entry->intf_link_addr.addr_type = + ADDR_TYPE_ETH; + entry->intf_link_addr.addr_bits = + ETH_ADDR_BITS; + } + eth_close(eth); + } + } + return (0); +} +#else +static int +_intf_get_noalias(intf_t *intf, struct intf_entry *entry) +{ + struct ifreq ifr; +#ifdef HAVE_GETKERNINFO + int size; + struct kinfo_ndd *nddp; + void *end; +#endif + + /* Get interface index. */ + entry->intf_index = if_nametoindex(entry->intf_name); + if (entry->intf_index == 0) + return (-1); + + strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); + + /* Get interface flags. */ + if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) + return (-1); + + entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags); + _intf_set_type(entry); + + /* Get interface MTU. */ +#ifdef SIOCGIFMTU + if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0) +#endif + return (-1); + entry->intf_mtu = ifr.ifr_mtu; + + entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = + entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; + + /* Get primary interface address. */ + if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) { + addr_ston(&ifr.ifr_addr, &entry->intf_addr); + if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0) + return (-1); + addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits); + } + /* Get other addresses. */ + if (entry->intf_type == INTF_TYPE_TUN) { + if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) { + if (addr_ston(&ifr.ifr_addr, + &entry->intf_dst_addr) < 0) + return (-1); + } + } else if (entry->intf_type == INTF_TYPE_ETH) { +#if defined(HAVE_GETKERNINFO) + /* AIX also defines SIOCGIFHWADDR, but it fails silently? + * This is the method IBM recommends here: + * http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.progcomm/doc/progcomc/skt_sndother_ex.htm%23ssqinc2joyc?lang=en + */ + /* How many bytes will be returned? */ + size = getkerninfo(KINFO_NDD, 0, 0, 0); + if (size <= 0) { + return -1; + } + nddp = (struct kinfo_ndd *)malloc(size); + + if (!nddp) { + return -1; + } + /* Get all Network Device Driver (NDD) info */ + if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) { + free(nddp); + return -1; + } + /* Loop over the returned values until we find a match */ + end = (void *)nddp + size; + while ((void *)nddp < end) { + if (!strcmp(nddp->ndd_alias, entry->intf_name) || + !strcmp(nddp->ndd_name, entry->intf_name)) { + addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS, + nddp->ndd_addr, ETH_ADDR_LEN); + break; + } else + nddp++; + } + free(nddp); +#elif defined(SIOCGIFHWADDR) + if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0) + return (-1); + if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0) { + /* Likely we got an unsupported address type. Just use NONE for now. */ + entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; + entry->intf_link_addr.addr_bits = 0; + } +#elif defined(SIOCRPHYSADDR) + /* Tru64 */ + struct ifdevea *ifd = (struct ifdevea *)𝔦 /* XXX */ + + if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0) + return (-1); + addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS, + ifd->current_pa, ETH_ADDR_LEN); +#else + eth_t *eth; + + if ((eth = eth_open(entry->intf_name)) != NULL) { + if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { + entry->intf_link_addr.addr_type = + ADDR_TYPE_ETH; + entry->intf_link_addr.addr_bits = + ETH_ADDR_BITS; + } + eth_close(eth); + } +#endif + } + return (0); +} +#endif + +#ifdef SIOCLIFADDR +/* XXX - aliases on IRIX don't show up in SIOCGIFCONF */ +static int +_intf_get_aliases(intf_t *intf, struct intf_entry *entry) +{ + struct dnet_ifaliasreq ifra; + struct addr *ap, *lap; + + strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); + addr_ntos(&entry->intf_addr, &ifra.ifra_addr); + addr_btos(entry->intf_addr.addr_bits, &ifra.ifra_mask); + memset(&ifra.ifra_brdaddr, 0, sizeof(ifra.ifra_brdaddr)); + ifra.ifra_cookie = 1; + + ap = entry->intf_alias_addrs; + lap = (struct addr *)((u_char *)entry + entry->intf_len); + + while (ioctl(intf->fd, SIOCLIFADDR, &ifra) == 0 && + ifra.ifra_cookie > 0 && (ap + 1) < lap) { + if (addr_ston(&ifra.ifra_addr, ap) < 0) + break; + ap++, entry->intf_alias_num++; + } + entry->intf_len = (u_char *)ap - (u_char *)entry; + + return (0); +} +#elif defined(SIOCGLIFCONF) +static int +_intf_get_aliases(intf_t *intf, struct intf_entry *entry) +{ + struct lifreq *lifr, *llifr; + struct lifreq tmplifr; + struct addr *ap, *lap; + char *p; + + if (intf->lifc.lifc_len < (int)sizeof(*lifr)) { + errno = EINVAL; + return (-1); + } + entry->intf_alias_num = 0; + ap = entry->intf_alias_addrs; + llifr = (struct lifreq *)intf->lifc.lifc_buf + + (intf->lifc.lifc_len / sizeof(*llifr)); + lap = (struct addr *)((u_char *)entry + entry->intf_len); + + /* Get addresses for this interface. */ + for (lifr = intf->lifc.lifc_req; lifr < llifr && (ap + 1) < lap; + lifr = NEXTLIFR(lifr)) { + /* XXX - Linux, Solaris ifaliases */ + if ((p = strchr(lifr->lifr_name, ':')) != NULL) + *p = '\0'; + + if (strcmp(lifr->lifr_name, entry->intf_name) != 0) { + if (p) *p = ':'; + continue; + } + + /* Fix the name back up */ + if (p) *p = ':'; + + if (addr_ston((struct sockaddr *)&lifr->lifr_addr, ap) < 0) + continue; + + /* XXX */ + if (ap->addr_type == ADDR_TYPE_ETH) { + memcpy(&entry->intf_link_addr, ap, sizeof(*ap)); + continue; + } else if (ap->addr_type == ADDR_TYPE_IP) { + if (ap->addr_ip == entry->intf_addr.addr_ip || + ap->addr_ip == entry->intf_dst_addr.addr_ip) + continue; + strlcpy(tmplifr.lifr_name, lifr->lifr_name, sizeof(tmplifr.lifr_name)); + if (ioctl(intf->fd, SIOCGIFNETMASK, &tmplifr) == 0) + addr_stob((struct sockaddr *)&tmplifr.lifr_addr, &ap->addr_bits); + } else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { + if (memcmp(&ap->addr_ip6, &entry->intf_addr.addr_ip6, IP6_ADDR_LEN) == 0 || + memcmp(&ap->addr_ip6, &entry->intf_dst_addr.addr_ip6, IP6_ADDR_LEN) == 0) + continue; + strlcpy(tmplifr.lifr_name, lifr->lifr_name, sizeof(tmplifr.lifr_name)); + if (ioctl(intf->fd6, SIOCGLIFNETMASK, &tmplifr) == 0) { + addr_stob((struct sockaddr *)&tmplifr.lifr_addr, + &ap->addr_bits); + } + else perror("SIOCGLIFNETMASK"); + } + ap++, entry->intf_alias_num++; + } + entry->intf_len = (u_char *)ap - (u_char *)entry; + + return (0); +} +#else +static int +_intf_get_aliases(intf_t *intf, struct intf_entry *entry) +{ + struct ifreq *ifr, *lifr; + struct ifreq tmpifr; + struct addr *ap, *lap; + char *p; + + if (intf->ifc.ifc_len < (int)sizeof(*ifr) && intf->ifc.ifc_len != 0) { + errno = EINVAL; + return (-1); + } + entry->intf_alias_num = 0; + ap = entry->intf_alias_addrs; + lifr = (struct ifreq *)intf->ifc.ifc_buf + + (intf->ifc.ifc_len / sizeof(*lifr)); + lap = (struct addr *)((u_char *)entry + entry->intf_len); + + /* Get addresses for this interface. */ + for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap; + ifr = NEXTIFR(ifr)) { + /* XXX - Linux, Solaris ifaliases */ + if ((p = strchr(ifr->ifr_name, ':')) != NULL) + *p = '\0'; + + if (strcmp(ifr->ifr_name, entry->intf_name) != 0) { + if (p) *p = ':'; + continue; + } + + /* Fix the name back up */ + if (p) *p = ':'; + + if (addr_ston(&ifr->ifr_addr, ap) < 0) + continue; + + /* XXX */ + if (ap->addr_type == ADDR_TYPE_ETH) { + memcpy(&entry->intf_link_addr, ap, sizeof(*ap)); + continue; + } else if (ap->addr_type == ADDR_TYPE_IP) { + if (ap->addr_ip == entry->intf_addr.addr_ip || + ap->addr_ip == entry->intf_dst_addr.addr_ip) + continue; + strlcpy(tmpifr.ifr_name, ifr->ifr_name, sizeof(tmpifr.ifr_name)); + if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0) + addr_stob(&tmpifr.ifr_addr, &ap->addr_bits); + } +#ifdef SIOCGIFNETMASK_IN6 + else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { + struct in6_ifreq ifr6; + + /* XXX - sizeof(ifr) < sizeof(ifr6) */ + memcpy(&ifr6, ifr, sizeof(ifr6)); + + if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) { + addr_stob((struct sockaddr *)&ifr6.ifr_addr, + &ap->addr_bits); + } + else perror("SIOCGIFNETMASK_IN6"); + } +#else +#ifdef SIOCGIFNETMASK6 + else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { + struct in6_ifreq ifr6; + + /* XXX - sizeof(ifr) < sizeof(ifr6) */ + memcpy(&ifr6, ifr, sizeof(ifr6)); + + if (ioctl(intf->fd6, SIOCGIFNETMASK6, &ifr6) == 0) { + /* For some reason this is 0 after the ioctl. */ + ifr6.ifr_Addr.sin6_family = AF_INET6; + addr_stob((struct sockaddr *)&ifr6.ifr_Addr, + &ap->addr_bits); + } + else perror("SIOCGIFNETMASK6"); + } +#endif +#endif + ap++, entry->intf_alias_num++; + } +#ifdef HAVE_LINUX_PROCFS +#define PROC_INET6_FILE "/proc/net/if_inet6" + { + FILE *f; + char buf[256], s[8][5], name[INTF_NAME_LEN]; + u_int idx, bits, scope, flags; + + if ((f = fopen(PROC_INET6_FILE, "r")) != NULL) { + while (ap < lap && + fgets(buf, sizeof(buf), f) != NULL) { + /* scan up to INTF_NAME_LEN-1 bytes to reserve space for null terminator */ + sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %x %02x %02x %02x %15s\n", + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], + &idx, &bits, &scope, &flags, name); + if (strcmp(name, entry->intf_name) == 0) { + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], bits); + addr_aton(buf, ap); + ap++, entry->intf_alias_num++; + } + } + fclose(f); + } + } +#endif + entry->intf_len = (u_char *)ap - (u_char *)entry; + + return (0); +} +#endif /* SIOCLIFADDR */ + +int +intf_get(intf_t *intf, struct intf_entry *entry) +{ + if (_intf_get_noalias(intf, entry) < 0) + return (-1); +#ifndef SIOCLIFADDR + intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf; + intf->ifc.ifc_len = sizeof(intf->ifcbuf); + + if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0) + return (-1); +#endif + return (_intf_get_aliases(intf, entry)); +} + +/* Look up an interface from an index, such as a sockaddr_in6.sin6_scope_id. */ +int +intf_get_index(intf_t *intf, struct intf_entry *entry, int af, unsigned int index) +{ + char namebuf[IFNAMSIZ]; + char *devname; + + /* af is ignored; only used in intf-win32.c. */ + devname = if_indextoname(index, namebuf); + if (devname == NULL) + return (-1); + strlcpy(entry->intf_name, devname, sizeof(entry->intf_name)); + return intf_get(intf, entry); +} + +static int +_match_intf_src(const struct intf_entry *entry, void *arg) +{ + struct intf_entry *save = (struct intf_entry *)arg; + int matched = 0, cnt; + + if (entry->intf_addr.addr_type == ADDR_TYPE_IP && + entry->intf_addr.addr_ip == save->intf_addr.addr_ip) + matched = 1; + + for (cnt = 0; !matched && cnt < (int) entry->intf_alias_num; cnt++) { + if (entry->intf_alias_addrs[cnt].addr_type != ADDR_TYPE_IP) + continue; + if (entry->intf_alias_addrs[cnt].addr_ip == save->intf_addr.addr_ip) + matched = 1; + } + + if (matched) { + /* XXX - truncated result if entry is too small. */ + if (save->intf_len < entry->intf_len) + memcpy(save, entry, save->intf_len); + else + memcpy(save, entry, entry->intf_len); + return (1); + } + return (0); +} + +int +intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src) +{ + memcpy(&entry->intf_addr, src, sizeof(*src)); + + if (intf_loop(intf, _match_intf_src, entry) != 1) { + errno = ENXIO; + return (-1); + } + return (0); +} + +int +intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst) +{ + struct sockaddr_in sin; + socklen_t n; + + if (dst->addr_type != ADDR_TYPE_IP) { + errno = EINVAL; + return (-1); + } + addr_ntos(dst, (struct sockaddr *)&sin); + sin.sin_port = htons(666); + + if (connect(intf->fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) + return (-1); + + n = sizeof(sin); + if (getsockname(intf->fd, (struct sockaddr *)&sin, &n) < 0) + return (-1); + + addr_ston((struct sockaddr *)&sin, &entry->intf_addr); + + if (intf_loop(intf, _match_intf_src, entry) != 1) + return (-1); + + return (0); +} + +#ifdef HAVE_LINUX_PROCFS +#define PROC_DEV_FILE "/proc/net/dev" + +int +intf_loop(intf_t *intf, intf_handler callback, void *arg) +{ + FILE *fp; + struct intf_entry *entry; + char *p, buf[BUFSIZ], ebuf[BUFSIZ]; + int ret; + + entry = (struct intf_entry *)ebuf; + + if ((fp = fopen(PROC_DEV_FILE, "r")) == NULL) + return (-1); + + intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf; + intf->ifc.ifc_len = sizeof(intf->ifcbuf); + + if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0) { + fclose(fp); + return (-1); + } + + ret = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((p = strchr(buf, ':')) == NULL) + continue; + *p = '\0'; + for (p = buf; *p == ' '; p++) + ; + + memset(ebuf, 0, sizeof(ebuf)); + strlcpy(entry->intf_name, p, sizeof(entry->intf_name)); + entry->intf_len = sizeof(ebuf); + + if (_intf_get_noalias(intf, entry) < 0) { + ret = -1; + break; + } + if (_intf_get_aliases(intf, entry) < 0) { + ret = -1; + break; + } + if ((ret = (*callback)(entry, arg)) != 0) + break; + } + if (ferror(fp)) + ret = -1; + + fclose(fp); + + return (ret); +} +#elif defined(SIOCGLIFCONF) +int +intf_loop(intf_t *intf, intf_handler callback, void *arg) +{ + struct intf_entry *entry; + struct lifreq *lifr, *llifr, *plifr; + char *p, ebuf[BUFSIZ]; + int ret; + struct lifreq lifrflags; + memset(&lifrflags, 0, sizeof(struct lifreq)); + + entry = (struct intf_entry *)ebuf; + + /* http://www.unix.com/man-page/opensolaris/7p/if_tcp */ + intf->lifc.lifc_family = AF_UNSPEC; + intf->lifc.lifc_flags = 0; +#ifdef LIFC_UNDER_IPMP + intf->lifc.lifc_flags |= LIFC_UNDER_IPMP; +#endif + intf->lifc.lifc_buf = (caddr_t)intf->ifcbuf; + intf->lifc.lifc_len = sizeof(intf->ifcbuf); + + if (ioctl(intf->fd, SIOCGLIFCONF, &intf->lifc) < 0) + return (-1); + + llifr = (struct lifreq *)&intf->lifc.lifc_buf[intf->lifc.lifc_len]; + + for (lifr = intf->lifc.lifc_req; lifr < llifr; lifr = NEXTLIFR(lifr)) { + /* XXX - Linux, Solaris ifaliases */ + if ((p = strchr(lifr->lifr_name, ':')) != NULL) + *p = '\0'; + + for (plifr = intf->lifc.lifc_req; plifr < lifr; plifr = NEXTLIFR(lifr)) { + if (strcmp(lifr->lifr_name, plifr->lifr_name) == 0) + break; + } + if (lifr > intf->lifc.lifc_req && plifr < lifr) + continue; + + memset(ebuf, 0, sizeof(ebuf)); + strlcpy(entry->intf_name, lifr->lifr_name, + sizeof(entry->intf_name)); + entry->intf_len = sizeof(ebuf); + + /* Repair the alias name back up */ + if (p) *p = ':'; + + /* Ignore IPMP interfaces. These are virtual interfaces made up + * of physical interfaces. IPMP interfaces do not support things + * like packet sniffing; it is necessary to use one of the + * underlying physical interfaces instead. This works as long as + * the physical interface's test address is on the same subnet + * as the IPMP interface's address. */ + strlcpy(lifrflags.lifr_name, lifr->lifr_name, sizeof(lifrflags.lifr_name)); + if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifrflags) >= 0) + ; + else if (intf->fd6 != -1 && ioctl(intf->fd6, SIOCGLIFFLAGS, &lifrflags) >= 0) + ; + else + return (-1); +#ifdef IFF_IPMP + if (lifrflags.lifr_flags & IFF_IPMP) { + continue; + } +#endif + + if (_intf_get_noalias(intf, entry) < 0) + return (-1); + if (_intf_get_aliases(intf, entry) < 0) + return (-1); + + if ((ret = (*callback)(entry, arg)) != 0) + return (ret); + } + return (0); +} +#else +int +intf_loop(intf_t *intf, intf_handler callback, void *arg) +{ + struct intf_entry *entry; + struct ifreq *ifr, *lifr, *pifr; + char *p, ebuf[BUFSIZ]; + int ret; + + entry = (struct intf_entry *)ebuf; + + intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf; + intf->ifc.ifc_len = sizeof(intf->ifcbuf); + + if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0) + return (-1); + + pifr = NULL; + lifr = (struct ifreq *)&intf->ifc.ifc_buf[intf->ifc.ifc_len]; + + for (ifr = intf->ifc.ifc_req; ifr < lifr; ifr = NEXTIFR(ifr)) { + /* XXX - Linux, Solaris ifaliases */ + if ((p = strchr(ifr->ifr_name, ':')) != NULL) + *p = '\0'; + + if (pifr != NULL && strcmp(ifr->ifr_name, pifr->ifr_name) == 0) { + if (p) *p = ':'; + continue; + } + + memset(ebuf, 0, sizeof(ebuf)); + strlcpy(entry->intf_name, ifr->ifr_name, + sizeof(entry->intf_name)); + entry->intf_len = sizeof(ebuf); + + /* Repair the alias name back up */ + if (p) *p = ':'; + + if (_intf_get_noalias(intf, entry) < 0) + return (-1); + if (_intf_get_aliases(intf, entry) < 0) + return (-1); + + if ((ret = (*callback)(entry, arg)) != 0) + return (ret); + + pifr = ifr; + } + return (0); +} +#endif /* !HAVE_LINUX_PROCFS */ + +intf_t * +intf_close(intf_t *intf) +{ + if (intf != NULL) { + if (intf->fd >= 0) + close(intf->fd); + if (intf->fd6 >= 0) + close(intf->fd6); + free(intf); + } + return (NULL); +} diff --git a/libdnet-stripped/src/ip-cooked.c b/libdnet-stripped/src/ip-cooked.c new file mode 100644 index 0000000..98f6e3e --- /dev/null +++ b/libdnet-stripped/src/ip-cooked.c @@ -0,0 +1,250 @@ +/* + * ip-cooked.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: ip-cooked.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#ifndef _WIN32 +#include <netinet/in.h> +#include <unistd.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" +#include "queue.h" + +struct ip_intf { + eth_t *eth; + char name[INTF_NAME_LEN]; + struct addr ha; + struct addr pa; + int mtu; + LIST_ENTRY(ip_intf) next; +}; + +struct ip_handle { + arp_t *arp; + intf_t *intf; + route_t *route; + int fd; + struct sockaddr_in sin; + + LIST_HEAD(, ip_intf) ip_intf_list; +}; + +static int +_add_ip_intf(const struct intf_entry *entry, void *arg) +{ + ip_t *ip = (ip_t *)arg; + struct ip_intf *ipi; + + if (entry->intf_type == INTF_TYPE_ETH && + (entry->intf_flags & INTF_FLAG_UP) != 0 && + entry->intf_mtu >= ETH_LEN_MIN && + entry->intf_addr.addr_type == ADDR_TYPE_IP && + entry->intf_link_addr.addr_type == ADDR_TYPE_ETH) { + + if ((ipi = calloc(1, sizeof(*ipi))) == NULL) + return (-1); + + strlcpy(ipi->name, entry->intf_name, sizeof(ipi->name)); + memcpy(&ipi->ha, &entry->intf_link_addr, sizeof(ipi->ha)); + memcpy(&ipi->pa, &entry->intf_addr, sizeof(ipi->pa)); + ipi->mtu = entry->intf_mtu; + + LIST_INSERT_HEAD(&ip->ip_intf_list, ipi, next); + } + return (0); +} + +ip_t * +ip_open(void) +{ + ip_t *ip; + + if ((ip = calloc(1, sizeof(*ip))) != NULL) { + ip->fd = -1; + + if ((ip->arp = arp_open()) == NULL || + (ip->intf = intf_open()) == NULL || + (ip->route = route_open()) == NULL) + return (ip_close(ip)); + + if ((ip->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (ip_close(ip)); + + memset(&ip->sin, 0, sizeof(ip->sin)); + ip->sin.sin_family = AF_INET; + ip->sin.sin_port = htons(666); + + LIST_INIT(&ip->ip_intf_list); + + if (intf_loop(ip->intf, _add_ip_intf, ip) != 0) + return (ip_close(ip)); + } + return (ip); +} + +static struct ip_intf * +_lookup_ip_intf(ip_t *ip, ip_addr_t dst) +{ + struct ip_intf *ipi; + int n; + + ip->sin.sin_addr.s_addr = dst; + n = sizeof(ip->sin); + + if (connect(ip->fd, (struct sockaddr *)&ip->sin, n) < 0) + return (NULL); + + if (getsockname(ip->fd, (struct sockaddr *)&ip->sin, &n) < 0) + return (NULL); + + LIST_FOREACH(ipi, &ip->ip_intf_list, next) { + if (ipi->pa.addr_ip == ip->sin.sin_addr.s_addr) { + if (ipi->eth == NULL) { + if ((ipi->eth = eth_open(ipi->name)) == NULL) + return (NULL); + } + if (ipi != LIST_FIRST(&ip->ip_intf_list)) { + LIST_REMOVE(ipi, next); + LIST_INSERT_HEAD(&ip->ip_intf_list, ipi, next); + } + return (ipi); + } + } + return (NULL); +} + +static void +_request_arp(struct ip_intf *ipi, struct addr *dst) +{ + u_char frame[ETH_HDR_LEN + ARP_HDR_LEN + ARP_ETHIP_LEN]; + + eth_pack_hdr(frame, ETH_ADDR_BROADCAST, ipi->ha.addr_eth, + ETH_TYPE_ARP); + arp_pack_hdr_ethip(frame + ETH_HDR_LEN, ARP_OP_REQUEST, + ipi->ha.addr_eth, ipi->pa.addr_ip, ETH_ADDR_BROADCAST, + dst->addr_ip); + + eth_send(ipi->eth, frame, sizeof(frame)); +} + +ssize_t +ip_send(ip_t *ip, const void *buf, size_t len) +{ + struct ip_hdr *iph; + struct ip_intf *ipi; + struct arp_entry arpent; + struct route_entry rtent; + u_char frame[ETH_LEN_MAX]; + int i, usec; + + iph = (struct ip_hdr *)buf; + + if ((ipi = _lookup_ip_intf(ip, iph->ip_dst)) == NULL) { + errno = EHOSTUNREACH; + return (-1); + } + arpent.arp_pa.addr_type = ADDR_TYPE_IP; + arpent.arp_pa.addr_bits = IP_ADDR_BITS; + arpent.arp_pa.addr_ip = iph->ip_dst; + memcpy(&rtent.route_dst, &arpent.arp_pa, sizeof(rtent.route_dst)); + + for (i = 0, usec = 10; i < 3; i++, usec *= 100) { + if (arp_get(ip->arp, &arpent) == 0) + break; + + if (route_get(ip->route, &rtent) == 0 && + rtent.route_gw.addr_ip != ipi->pa.addr_ip) { + memcpy(&arpent.arp_pa, &rtent.route_gw, + sizeof(arpent.arp_pa)); + if (arp_get(ip->arp, &arpent) == 0) + break; + } + _request_arp(ipi, &arpent.arp_pa); + + usleep(usec); + } + if (i == 3) + memset(&arpent.arp_ha.addr_eth, 0xff, ETH_ADDR_LEN); + + eth_pack_hdr(frame, arpent.arp_ha.addr_eth, + ipi->ha.addr_eth, ETH_TYPE_IP); + + if (len > ipi->mtu) { + u_char *p, *start, *end, *ip_data; + int ip_hl, fraglen; + + ip_hl = iph->ip_hl << 2; + fraglen = ipi->mtu - ip_hl; + + iph = (struct ip_hdr *)(frame + ETH_HDR_LEN); + memcpy(iph, buf, ip_hl); + ip_data = (u_char *)iph + ip_hl; + + start = (u_char *)buf + ip_hl; + end = (u_char *)buf + len; + + for (p = start; p < end; ) { + memcpy(ip_data, p, fraglen); + + iph->ip_len = htons(ip_hl + fraglen); + iph->ip_off = htons(((p + fraglen < end) ? IP_MF : 0) | + ((p - start) >> 3)); + + ip_checksum(iph, ip_hl + fraglen); + + i = ETH_HDR_LEN + ip_hl + fraglen; + if (eth_send(ipi->eth, frame, i) != i) + return (-1); + p += fraglen; + if (end - p < fraglen) + fraglen = end - p; + } + return (len); + } + memcpy(frame + ETH_HDR_LEN, buf, len); + i = ETH_HDR_LEN + len; + if (eth_send(ipi->eth, frame, i) != i) + return (-1); + + return (len); +} + +ip_t * +ip_close(ip_t *ip) +{ + struct ip_intf *ipi, *nxt; + + if (ip != NULL) { + for (ipi = LIST_FIRST(&ip->ip_intf_list); + ipi != LIST_END(&ip->ip_intf_list); ipi = nxt) { + nxt = LIST_NEXT(ipi, next); + if (ipi->eth != NULL) + eth_close(ipi->eth); + free(ipi); + } + if (ip->fd >= 0) + close(ip->fd); + if (ip->route != NULL) + route_close(ip->route); + if (ip->intf != NULL) + intf_close(ip->intf); + if (ip->arp != NULL) + arp_close(ip->arp); + free(ip); + } + return (NULL); +} diff --git a/libdnet-stripped/src/ip-util.c b/libdnet-stripped/src/ip-util.c new file mode 100644 index 0000000..280f0ee --- /dev/null +++ b/libdnet-stripped/src/ip-util.c @@ -0,0 +1,217 @@ +/* + * ip-util.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: ip-util.c 595 2005-02-17 02:55:56Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" +#include "crc32ct.h" + +/* CRC-32C (Castagnoli). Public domain. */ +static unsigned long +_crc32c(unsigned char *buf, int len) +{ + int i; + unsigned long crc32 = ~0L; + unsigned long result; + unsigned char byte0, byte1, byte2, byte3; + + for (i = 0; i < len; i++) { + CRC32C(crc32, buf[i]); + } + + result = ~crc32; + + byte0 = result & 0xff; + byte1 = (result >> 8) & 0xff; + byte2 = (result >> 16) & 0xff; + byte3 = (result >> 24) & 0xff; + crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); + return crc32; +} + +ssize_t +ip_add_option(void *buf, size_t len, int proto, + const void *optbuf, size_t optlen) +{ + struct ip_hdr *ip; + struct tcp_hdr *tcp = NULL; + u_char *p; + int hl, datalen, padlen; + + if (proto != IP_PROTO_IP && proto != IP_PROTO_TCP) { + errno = EINVAL; + return (-1); + } + ip = (struct ip_hdr *)buf; + hl = ip->ip_hl << 2; + p = (u_char *)buf + hl; + + if (proto == IP_PROTO_TCP) { + tcp = (struct tcp_hdr *)p; + hl = tcp->th_off << 2; + p = (u_char *)tcp + hl; + } + datalen = (int) (ntohs(ip->ip_len) - (p - (u_char *)buf)); + + /* Compute padding to next word boundary. */ + if ((padlen = 4 - (optlen % 4)) == 4) + padlen = 0; + + /* XXX - IP_HDR_LEN_MAX == TCP_HDR_LEN_MAX */ + if (hl + optlen + padlen > IP_HDR_LEN_MAX || + ntohs(ip->ip_len) + optlen + padlen > len) { + errno = EINVAL; + return (-1); + } + /* XXX - IP_OPT_TYPEONLY() == TCP_OPT_TYPEONLY */ + if (IP_OPT_TYPEONLY(((struct ip_opt *)optbuf)->opt_type)) + optlen = 1; + + /* Shift any existing data. */ + if (datalen) { + memmove(p + optlen + padlen, p, datalen); + } + /* XXX - IP_OPT_NOP == TCP_OPT_NOP */ + if (padlen) { + memset(p, IP_OPT_NOP, padlen); + p += padlen; + } + memmove(p, optbuf, optlen); + p += optlen; + optlen += padlen; + + if (proto == IP_PROTO_IP) + ip->ip_hl = (int) ((p - (u_char *)ip) >> 2); + else if (proto == IP_PROTO_TCP) + tcp->th_off = (int) ((p - (u_char *)tcp) >> 2); + + ip->ip_len = htons((u_short) (ntohs(ip->ip_len) + optlen)); + + return (ssize_t)(optlen); +} + +void +ip_checksum(void *buf, size_t len) +{ + struct ip_hdr *ip; + int hl, off, sum; + + if (len < IP_HDR_LEN) + return; + + ip = (struct ip_hdr *)buf; + hl = ip->ip_hl << 2; + ip->ip_sum = 0; + sum = ip_cksum_add(ip, hl, 0); + ip->ip_sum = ip_cksum_carry(sum); + + off = htons(ip->ip_off); + + if ((off & IP_OFFMASK) != 0 || (off & IP_MF) != 0) + return; + + len -= hl; + + if (ip->ip_p == IP_PROTO_TCP) { + struct tcp_hdr *tcp = (struct tcp_hdr *)((u_char *)ip + hl); + + if (len >= TCP_HDR_LEN) { + tcp->th_sum = 0; + sum = ip_cksum_add(tcp, len, 0) + + htons((u_short)(ip->ip_p + len)); + sum = ip_cksum_add(&ip->ip_src, 8, sum); + tcp->th_sum = ip_cksum_carry(sum); + } + } else if (ip->ip_p == IP_PROTO_UDP) { + struct udp_hdr *udp = (struct udp_hdr *)((u_char *)ip + hl); + + if (len >= UDP_HDR_LEN) { + udp->uh_sum = 0; + sum = ip_cksum_add(udp, len, 0) + + htons((u_short)(ip->ip_p + len)); + sum = ip_cksum_add(&ip->ip_src, 8, sum); + udp->uh_sum = ip_cksum_carry(sum); + if (!udp->uh_sum) + udp->uh_sum = 0xffff; /* RFC 768 */ + } + } else if (ip->ip_p == IP_PROTO_SCTP) { + struct sctp_hdr *sctp = (struct sctp_hdr *)((u_char *)ip + hl); + + if (len >= SCTP_HDR_LEN) { + sctp->sh_sum = 0; + sctp->sh_sum = htonl(_crc32c((u_char *)sctp, len)); + } + } else if (ip->ip_p == IP_PROTO_ICMP || ip->ip_p == IP_PROTO_IGMP) { + struct icmp_hdr *icmp = (struct icmp_hdr *)((u_char *)ip + hl); + + if (len >= ICMP_HDR_LEN) { + icmp->icmp_cksum = 0; + sum = ip_cksum_add(icmp, len, 0); + icmp->icmp_cksum = ip_cksum_carry(sum); + } + } +} + +int +ip_cksum_add(const void *buf, size_t len, int cksum) +{ + uint16_t *sp = (uint16_t *)buf; + int n, sn; + + sn = (int) len / 2; + n = (sn + 15) / 16; + + /* XXX - unroll loop using Duff's device. */ + switch (sn % 16) { + case 0: do { + cksum += *sp++; + case 15: + cksum += *sp++; + case 14: + cksum += *sp++; + case 13: + cksum += *sp++; + case 12: + cksum += *sp++; + case 11: + cksum += *sp++; + case 10: + cksum += *sp++; + case 9: + cksum += *sp++; + case 8: + cksum += *sp++; + case 7: + cksum += *sp++; + case 6: + cksum += *sp++; + case 5: + cksum += *sp++; + case 4: + cksum += *sp++; + case 3: + cksum += *sp++; + case 2: + cksum += *sp++; + case 1: + cksum += *sp++; + } while (--n > 0); + } + if (len & 1) + cksum += htons(*(u_char *)sp << 8); + + return (cksum); +} diff --git a/libdnet-stripped/src/ip-win32.c b/libdnet-stripped/src/ip-win32.c new file mode 100644 index 0000000..8f2ae84 --- /dev/null +++ b/libdnet-stripped/src/ip-win32.c @@ -0,0 +1,79 @@ +/* + * ip-win32.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: ip-win32.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <ws2tcpip.h> + +#include <errno.h> +#include <stdlib.h> + +#include "dnet.h" + +struct ip_handle { + WSADATA wsdata; + SOCKET fd; + struct sockaddr_in sin; +}; + +ip_t * +ip_open(void) +{ + BOOL on; + ip_t *ip; + + if ((ip = calloc(1, sizeof(*ip))) != NULL) { + if (WSAStartup(MAKEWORD(2, 2), &ip->wsdata) != 0) { + free(ip); + return (NULL); + } + if ((ip->fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == + INVALID_SOCKET) + return (ip_close(ip)); + + on = TRUE; + if (setsockopt(ip->fd, IPPROTO_IP, IP_HDRINCL, + (const char *)&on, sizeof(on)) == SOCKET_ERROR) { + SetLastError(ERROR_NETWORK_ACCESS_DENIED); + return (ip_close(ip)); + } + ip->sin.sin_family = AF_INET; + ip->sin.sin_port = htons(666); + } + return (ip); +} + +ssize_t +ip_send(ip_t *ip, const void *buf, size_t len) +{ + struct ip_hdr *hdr = (struct ip_hdr *)buf; + + ip->sin.sin_addr.s_addr = hdr->ip_src; + + if ((len = sendto(ip->fd, (const char *)buf, (int)len, 0, + (struct sockaddr *)&ip->sin, sizeof(ip->sin))) != SOCKET_ERROR) + return (ssize_t)(len); + + return (-1); +} + +ip_t * +ip_close(ip_t *ip) +{ + if (ip != NULL) { + WSACleanup(); + if (ip->fd != INVALID_SOCKET) + closesocket(ip->fd); + free(ip); + } + return (NULL); +} diff --git a/libdnet-stripped/src/ip.c b/libdnet-stripped/src/ip.c new file mode 100644 index 0000000..6b513ce --- /dev/null +++ b/libdnet-stripped/src/ip.c @@ -0,0 +1,104 @@ +/* + * ip.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: ip.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#include "config.h" + +#include <netinet/in.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct ip_handle { + int fd; +}; + +ip_t * +ip_open(void) +{ + ip_t *i; + int n; + socklen_t len; + + if ((i = calloc(1, sizeof(*i))) == NULL) + return (NULL); + + if ((i->fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + return (ip_close(i)); +#ifdef IP_HDRINCL + n = 1; + if (setsockopt(i->fd, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n)) < 0) + return (ip_close(i)); +#endif +#ifdef SO_SNDBUF + len = sizeof(n); + if (getsockopt(i->fd, SOL_SOCKET, SO_SNDBUF, &n, &len) < 0) + return (ip_close(i)); + + for (n += 128; n < 1048576; n += 128) { + if (setsockopt(i->fd, SOL_SOCKET, SO_SNDBUF, &n, len) < 0) { + if (errno == ENOBUFS) + break; + return (ip_close(i)); + } + } +#endif +#ifdef SO_BROADCAST + n = 1; + if (setsockopt(i->fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)) < 0) + return (ip_close(i)); +#endif + return (i); +} + +ssize_t +ip_send(ip_t *i, const void *buf, size_t len) +{ + struct ip_hdr *ip; + struct sockaddr_in sin; + + ip = (struct ip_hdr *)buf; + + memset(&sin, 0, sizeof(sin)); +#ifdef HAVE_SOCKADDR_SA_LEN + sin.sin_len = sizeof(sin); +#endif + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ip->ip_dst; + +#ifdef HAVE_RAWIP_HOST_OFFLEN + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + + len = sendto(i->fd, buf, len, 0, + (struct sockaddr *)&sin, sizeof(sin)); + + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + + return (len); +#else + return (sendto(i->fd, buf, len, 0, + (struct sockaddr *)&sin, sizeof(sin))); +#endif +} + +ip_t * +ip_close(ip_t *i) +{ + if (i != NULL) { + if (i->fd >= 0) + close(i->fd); + free(i); + } + return (NULL); +} diff --git a/libdnet-stripped/src/ip6.c b/libdnet-stripped/src/ip6.c new file mode 100644 index 0000000..b5f474b --- /dev/null +++ b/libdnet-stripped/src/ip6.c @@ -0,0 +1,76 @@ +/* + * ip6.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: ip6.c 539 2005-01-23 07:36:54Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include "dnet.h" + +#define IP6_IS_EXT(n) \ + ((n) == IP_PROTO_HOPOPTS || (n) == IP_PROTO_DSTOPTS || \ + (n) == IP_PROTO_ROUTING || (n) == IP_PROTO_FRAGMENT) + +void +ip6_checksum(void *buf, size_t len) +{ + struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; + struct ip6_ext_hdr *ext; + u_char *p, nxt; + int i, sum; + + nxt = ip6->ip6_nxt; + + for (i = IP6_HDR_LEN; IP6_IS_EXT(nxt); i += (ext->ext_len + 1) << 3) { + if (i >= (int)len) return; + ext = (struct ip6_ext_hdr *)((u_char *)buf + i); + nxt = ext->ext_nxt; + } + p = (u_char *)buf + i; + len -= i; + + if (nxt == IP_PROTO_TCP) { + struct tcp_hdr *tcp = (struct tcp_hdr *)p; + + if (len >= TCP_HDR_LEN) { + tcp->th_sum = 0; + sum = ip_cksum_add(tcp, len, 0) + htons(nxt + (u_short)len); + sum = ip_cksum_add(&ip6->ip6_src, 32, sum); + tcp->th_sum = ip_cksum_carry(sum); + } + } else if (nxt == IP_PROTO_UDP) { + struct udp_hdr *udp = (struct udp_hdr *)p; + + if (len >= UDP_HDR_LEN) { + udp->uh_sum = 0; + sum = ip_cksum_add(udp, len, 0) + htons(nxt + (u_short)len); + sum = ip_cksum_add(&ip6->ip6_src, 32, sum); + if ((udp->uh_sum = ip_cksum_carry(sum)) == 0) + udp->uh_sum = 0xffff; + } + } else if (nxt == IP_PROTO_ICMPV6) { + struct icmp_hdr *icmp = (struct icmp_hdr *)p; + + if (len >= ICMP_HDR_LEN) { + icmp->icmp_cksum = 0; + sum = ip_cksum_add(icmp, len, 0) + htons(nxt + (u_short)len); + sum = ip_cksum_add(&ip6->ip6_src, 32, sum); + icmp->icmp_cksum = ip_cksum_carry(sum); + } + } else if (nxt == IP_PROTO_ICMP || nxt == IP_PROTO_IGMP) { + struct icmp_hdr *icmp = (struct icmp_hdr *)p; + + if (len >= ICMP_HDR_LEN) { + icmp->icmp_cksum = 0; + sum = ip_cksum_add(icmp, len, 0); + icmp->icmp_cksum = ip_cksum_carry(sum); + } + } +} diff --git a/libdnet-stripped/src/memcmp.c b/libdnet-stripped/src/memcmp.c new file mode 100644 index 0000000..5ce33e2 --- /dev/null +++ b/libdnet-stripped/src/memcmp.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: memcmp.c,v 1.2 1996/08/19 08:34:05 tholo Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <string.h> + +/* + * Compare memory regions. + */ +int +memcmp(s1, s2, n) + const void *s1, *s2; + size_t n; +{ + if (n != 0) { + register const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return (0); +} diff --git a/libdnet-stripped/src/rand.c b/libdnet-stripped/src/rand.c new file mode 100644 index 0000000..9095ad8 --- /dev/null +++ b/libdnet-stripped/src/rand.c @@ -0,0 +1,208 @@ +/* + * rand.c + * + * Pseudorandom number generation, based on OpenBSD arc4random(). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * Copyright (c) 1996 David Mazieres <dm@lcs.mit.edu> + * + * $Id: rand.c 587 2005-02-15 06:37:07Z dugsong $ + */ + +#include "config.h" + +#ifdef _WIN32 +/* XXX */ +# undef _WIN32_WINNT +# define _WIN32_WINNT _WIN32_WINNT_WIN7 +# include <bcrypt.h> +# pragma comment(lib, "bcrypt.lib") +# define inline __inline +#else +# include <sys/types.h> +# include <sys/time.h> +# include <unistd.h> +#endif +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +struct rand_handle { + uint8_t i; + uint8_t j; + uint8_t s[256]; + u_char *tmp; + int tmplen; +}; + +static inline void +rand_init(rand_t *rand) +{ + int i; + + for (i = 0; i < 256; i++) + rand->s[i] = i; + rand->i = rand->j = 0; +} + +static inline void +rand_addrandom(rand_t *rand, u_char *buf, int len) +{ + int i; + uint8_t si; + + rand->i--; + for (i = 0; i < 256; i++) { + rand->i = (rand->i + 1); + si = rand->s[rand->i]; + rand->j = (rand->j + si + buf[i % len]); + rand->s[rand->i] = rand->s[rand->j]; + rand->s[rand->j] = si; + } + rand->j = rand->i; +} + +rand_t * +rand_open(void) +{ + rand_t *r; + u_char seed[256]; +#ifdef _WIN32 + if (STATUS_SUCCESS != BCryptGenRandom(NULL, seed, sizeof(seed), BCRYPT_USE_SYSTEM_PREFERRED_RNG)) + return NULL; +#else + struct timeval *tv = (struct timeval *)seed; + int fd; + + if ((fd = open("/dev/arandom", O_RDONLY)) != -1 || + (fd = open("/dev/urandom", O_RDONLY)) != -1) { + read(fd, seed + sizeof(*tv), sizeof(seed) - sizeof(*tv)); + close(fd); + } + gettimeofday(tv, NULL); +#endif + if ((r = malloc(sizeof(*r))) != NULL) { + rand_init(r); + rand_addrandom(r, seed, 128); + rand_addrandom(r, seed + 128, 128); + r->tmp = NULL; + r->tmplen = 0; + } + return (r); +} + +static uint8_t +rand_getbyte(rand_t *r) +{ + uint8_t si, sj; + + r->i = (r->i + 1); + si = r->s[r->i]; + r->j = (r->j + si); + sj = r->s[r->j]; + r->s[r->i] = sj; + r->s[r->j] = si; + return (r->s[(si + sj) & 0xff]); +} + +int +rand_get(rand_t *r, void *buf, size_t len) +{ + u_char *p; + u_int i; + + for (p = buf, i = 0; i < len; i++) { + p[i] = rand_getbyte(r); + } + return (0); +} + +int +rand_set(rand_t *r, const void *buf, size_t len) +{ + rand_init(r); + rand_addrandom(r, (u_char *)buf, len); + rand_addrandom(r, (u_char *)buf, len); + return (0); +} + +int +rand_add(rand_t *r, const void *buf, size_t len) +{ + rand_addrandom(r, (u_char *)buf, len); + return (0); +} + +uint8_t +rand_uint8(rand_t *r) +{ + return (rand_getbyte(r)); +} + +uint16_t +rand_uint16(rand_t *r) +{ + uint16_t val; + + val = rand_getbyte(r) << 8; + val |= rand_getbyte(r); + return (val); +} + +uint32_t +rand_uint32(rand_t *r) +{ + uint32_t val; + + val = rand_getbyte(r) << 24; + val |= rand_getbyte(r) << 16; + val |= rand_getbyte(r) << 8; + val |= rand_getbyte(r); + return (val); +} + +int +rand_shuffle(rand_t *r, void *base, size_t nmemb, size_t size) +{ + u_char *save, *src, *dst, *start = (u_char *)base; + u_int i, j; + + if (nmemb < 2) + return (0); + + if ((u_int)r->tmplen < size) { + if (r->tmp == NULL) { + if ((save = malloc(size)) == NULL) + return (-1); + } else if ((save = realloc(r->tmp, size)) == NULL) + return (-1); + + r->tmp = save; + r->tmplen = size; + } else + save = r->tmp; + + for (i = 0; i < nmemb; i++) { + if ((j = rand_uint32(r) % (nmemb - 1)) != i) { + src = start + (size * i); + dst = start + (size * j); + memcpy(save, dst, size); + memcpy(dst, src, size); + memcpy(src, save, size); + } + } + return (0); +} + +rand_t * +rand_close(rand_t *r) +{ + if (r != NULL) { + if (r->tmp != NULL) + free(r->tmp); + free(r); + } + return (NULL); +} diff --git a/libdnet-stripped/src/route-bsd.c b/libdnet-stripped/src/route-bsd.c new file mode 100644 index 0000000..2ca799c --- /dev/null +++ b/libdnet-stripped/src/route-bsd.c @@ -0,0 +1,703 @@ +/* + * route-bsd.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * Copyright (c) 1999 Masaki Hirabaru <masaki@merit.edu> + * + * $Id: route-bsd.c 555 2005-02-10 05:18:38Z dugsong $ + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifdef HAVE_STREAMS_MIB2 +#include <sys/stream.h> +#include <sys/tihdr.h> +#include <sys/tiuser.h> +#include <inet/common.h> +#include <inet/mib2.h> +#include <inet/ip.h> +#undef IP_ADDR_LEN +#include <stropts.h> +#elif defined(HAVE_STREAMS_ROUTE) +#include <sys/stream.h> +#include <sys/stropts.h> +#endif +#ifdef HAVE_GETKERNINFO +#include <sys/kinfo.h> +#endif + +#define route_t oroute_t /* XXX - unixware */ +#include <net/route.h> +#undef route_t +#include <net/if.h> +#include <netinet/in.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +#if defined(RT_ROUNDUP) && defined(__NetBSD__) +/* NetBSD defines this macro rounding to 64-bit boundaries. + http://fxr.watson.org/fxr/ident?v=NETBSD;i=RT_ROUNDUP */ +#define ROUNDUP(a) RT_ROUNDUP(a) +#else +/* Unix Network Programming, 3rd edition says that sockaddr structures in + rt_msghdr should be padded so their addresses start on a multiple of + sizeof(u_long). But on 64-bit Mac OS X 10.6 at least, this is false. Apple's + netstat code uses 4-byte padding, not 8-byte. This is relevant for IPv6 + addresses, for which sa_len == 28. + http://www.opensource.apple.com/source/network_cmds/network_cmds-329.2.2/netstat.tproj/route.c */ +#ifdef __APPLE__ +#define RT_MSGHDR_ALIGNMENT sizeof(uint32_t) +#else +#define RT_MSGHDR_ALIGNMENT sizeof(unsigned long) +#endif +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (RT_MSGHDR_ALIGNMENT - 1))) : RT_MSGHDR_ALIGNMENT) +#endif + +#ifdef HAVE_SOCKADDR_SA_LEN +#define NEXTSA(s) \ + ((struct sockaddr *)((u_char *)(s) + ROUNDUP((s)->sa_len))) +#else +#define NEXTSA(s) \ + ((struct sockaddr *)((u_char *)(s) + ROUNDUP(sizeof(*(s))))) +#endif + +struct route_handle { + int fd; + int seq; +#ifdef HAVE_STREAMS_MIB2 + int ip_fd; +#endif +}; + +#ifdef DEBUG +static void +route_msg_print(struct rt_msghdr *rtm) +{ + printf("v: %d type: 0x%x flags: 0x%x addrs: 0x%x pid: %d seq: %d\n", + rtm->rtm_version, rtm->rtm_type, rtm->rtm_flags, + rtm->rtm_addrs, rtm->rtm_pid, rtm->rtm_seq); +} +#endif + +static int +route_msg(route_t *r, int type, char intf_name[INTF_NAME_LEN], struct addr *dst, struct addr *gw) +{ + struct addr net; + struct rt_msghdr *rtm; + struct sockaddr *sa; + u_char buf[BUFSIZ]; + pid_t pid; + int len; + + memset(buf, 0, sizeof(buf)); + + rtm = (struct rt_msghdr *)buf; + rtm->rtm_version = RTM_VERSION; + if ((rtm->rtm_type = type) != RTM_DELETE) + rtm->rtm_flags = RTF_UP; + rtm->rtm_addrs = RTA_DST; + rtm->rtm_seq = ++r->seq; + + /* Destination */ + sa = (struct sockaddr *)(rtm + 1); + if (addr_net(dst, &net) < 0 || addr_ntos(&net, sa) < 0) + return (-1); + sa = NEXTSA(sa); + + /* Gateway */ + if (gw != NULL && type != RTM_GET) { + rtm->rtm_flags |= RTF_GATEWAY; + rtm->rtm_addrs |= RTA_GATEWAY; + if (addr_ntos(gw, sa) < 0) + return (-1); + sa = NEXTSA(sa); + } + /* Netmask */ + if (dst->addr_ip == IP_ADDR_ANY || dst->addr_bits < IP_ADDR_BITS) { + rtm->rtm_addrs |= RTA_NETMASK; + if (addr_btos(dst->addr_bits, sa) < 0) + return (-1); + sa = NEXTSA(sa); + } else + rtm->rtm_flags |= RTF_HOST; + + rtm->rtm_msglen = (u_char *)sa - buf; +#ifdef DEBUG + route_msg_print(rtm); +#endif +#ifdef HAVE_STREAMS_ROUTE + if (ioctl(r->fd, RTSTR_SEND, rtm) < 0) + return (-1); +#else + if (write(r->fd, buf, rtm->rtm_msglen) < 0) + return (-1); + + pid = getpid(); + + while (type == RTM_GET && (len = read(r->fd, buf, sizeof(buf))) > 0) { + if (len < (int)sizeof(*rtm)) { + return (-1); + } + if (rtm->rtm_type == type && rtm->rtm_pid == pid && + rtm->rtm_seq == r->seq) { + if (rtm->rtm_errno) { + errno = rtm->rtm_errno; + return (-1); + } + break; + } + } +#endif + if (type == RTM_GET && (rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == + (RTA_DST|RTA_GATEWAY)) { + sa = (struct sockaddr *)(rtm + 1); + sa = NEXTSA(sa); + + if (addr_ston(sa, gw) < 0 || gw->addr_type != ADDR_TYPE_IP) { + errno = ESRCH; + return (-1); + } + + if (intf_name != NULL) { + char namebuf[IF_NAMESIZE]; + + if (if_indextoname(rtm->rtm_index, namebuf) == NULL) { + errno = ESRCH; + return (-1); + } + strlcpy(intf_name, namebuf, INTF_NAME_LEN); + } + } + return (0); +} + +route_t * +route_open(void) +{ + route_t *r; + + if ((r = calloc(1, sizeof(*r))) != NULL) { + r->fd = -1; +#ifdef HAVE_STREAMS_MIB2 + if ((r->ip_fd = open(IP_DEV_NAME, O_RDWR)) < 0) + return (route_close(r)); +#endif +#ifdef HAVE_STREAMS_ROUTE + if ((r->fd = open("/dev/route", O_RDWR, 0)) < 0) +#else + if ((r->fd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) +#endif + return (route_close(r)); + } + return (r); +} + +int +route_add(route_t *r, const struct route_entry *entry) +{ + struct route_entry rtent; + + memcpy(&rtent, entry, sizeof(rtent)); + + if (route_msg(r, RTM_ADD, NULL, &rtent.route_dst, &rtent.route_gw) < 0) + return (-1); + + return (0); +} + +int +route_delete(route_t *r, const struct route_entry *entry) +{ + struct route_entry rtent; + + memcpy(&rtent, entry, sizeof(rtent)); + + if (route_get(r, &rtent) < 0) + return (-1); + + if (route_msg(r, RTM_DELETE, NULL, &rtent.route_dst, &rtent.route_gw) < 0) + return (-1); + + return (0); +} + +int +route_get(route_t *r, struct route_entry *entry) +{ + if (route_msg(r, RTM_GET, entry->intf_name, &entry->route_dst, &entry->route_gw) < 0) + return (-1); + entry->intf_name[0] = '\0'; + entry->metric = 0; + + return (0); +} + +#if defined(HAVE_SYS_SYSCTL_H) || defined(HAVE_STREAMS_ROUTE) || defined(HAVE_GETKERNINFO) +/* This wrapper around addr_ston, on failure, checks for a gateway address + * family of AF_LINK, and if it finds one, stores an all-zero address of the + * same type as dst. The all-zero address is a convention for same-subnet + * routing table entries. */ +static int +addr_ston_gateway(const struct addr *dst, + const struct sockaddr *sa, struct addr *a) +{ + int rc; + + rc = addr_ston(sa, a); + if (rc == 0) + return rc; + +#ifdef HAVE_NET_IF_DL_H +# ifdef AF_LINK + if (sa->sa_family == AF_LINK) { + memset(a, 0, sizeof(*a)); + a->addr_type = dst->addr_type; + return (0); + } +# endif +#endif + + return (-1); +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + struct rt_msghdr *rtm; + struct route_entry entry; + struct sockaddr *sa; + char *buf, *lim, *next; + int ret; +#ifdef HAVE_SYS_SYSCTL_H + int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 }; + size_t len; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return (-1); + + if (len == 0) + return (0); + + if ((buf = malloc(len)) == NULL) + return (-1); + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return (-1); + } + lim = buf + len; + next = buf; +#elif defined(HAVE_GETKERNINFO) + int len = getkerninfo(KINFO_RT_DUMP,0,0,0); + + if (len == 0) + return (0); + + if ((buf = malloc(len)) == NULL) + return (-1); + + if (getkerninfo(KINFO_RT_DUMP,buf,&len,0) < 0) { + free(buf); + return (-1); + } + lim = buf + len; + next = buf; +#else /* HAVE_STREAMS_ROUTE */ + struct rt_giarg giarg, *gp; + + memset(&giarg, 0, sizeof(giarg)); + giarg.gi_op = KINFO_RT_DUMP; + + if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0) + return (-1); + + if ((buf = malloc(giarg.gi_size)) == NULL) + return (-1); + + gp = (struct rt_giarg *)buf; + gp->gi_size = giarg.gi_size; + gp->gi_op = KINFO_RT_DUMP; + gp->gi_where = buf; + gp->gi_arg = RTF_UP | RTF_GATEWAY; + + if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) { + free(buf); + return (-1); + } + lim = buf + gp->gi_size; + next = buf + sizeof(giarg); +#endif + /* This loop assumes that RTA_DST, RTA_GATEWAY, and RTA_NETMASK have the + * values, 1, 2, and 4 respectively. Cf. Unix Network Programming, + * p. 494, function get_rtaddrs. */ + for (ret = 0; next < lim; next += rtm->rtm_msglen) { + char namebuf[IF_NAMESIZE]; + sa_family_t sfam; + rtm = (struct rt_msghdr *)next; + sa = (struct sockaddr *)(rtm + 1); + /* peek at address family */ + sfam = sa->sa_family; + + if (if_indextoname(rtm->rtm_index, namebuf) == NULL) + continue; + strlcpy(entry.intf_name, namebuf, sizeof(entry.intf_name)); + + if ((rtm->rtm_addrs & RTA_DST) == 0) + /* Need a destination. */ + continue; + if (addr_ston(sa, &entry.route_dst) < 0) + continue; + + if ((rtm->rtm_addrs & RTA_GATEWAY) == 0) + /* Need a gateway. */ + continue; + sa = NEXTSA(sa); + if (addr_ston_gateway(&entry.route_dst, sa, &entry.route_gw) < 0) + continue; + + if (entry.route_dst.addr_type != entry.route_gw.addr_type || + (entry.route_dst.addr_type != ADDR_TYPE_IP && + entry.route_dst.addr_type != ADDR_TYPE_IP6)) + continue; + + if (rtm->rtm_addrs & RTA_NETMASK) { + sa = NEXTSA(sa); + /* FreeBSD for IPv6 uses a different AF for netmasks. Force the same one. */ + sa->sa_family = sfam; + if (addr_stob(sa, &entry.route_dst.addr_bits) < 0) + continue; + } + + entry.metric = 0; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + free(buf); + + return (ret); +} +#elif defined(HAVE_STREAMS_MIB2) + +#ifdef IRE_DEFAULT /* This means Solaris 5.6 */ +/* I'm not sure if they are compatible, though -- masaki */ +#define IRE_ROUTE IRE_CACHE +#define IRE_ROUTE_REDIRECT IRE_HOST_REDIRECT +#endif /* IRE_DEFAULT */ + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + struct route_entry entry; + struct strbuf msg; + struct T_optmgmt_req *tor; + struct T_optmgmt_ack *toa; + struct T_error_ack *tea; + struct opthdr *opt; + u_char buf[8192]; + int flags, rc, rtable, ret; + + tor = (struct T_optmgmt_req *)buf; + toa = (struct T_optmgmt_ack *)buf; + tea = (struct T_error_ack *)buf; + + tor->PRIM_type = T_OPTMGMT_REQ; + tor->OPT_offset = sizeof(*tor); + tor->OPT_length = sizeof(*opt); + tor->MGMT_flags = T_CURRENT; + + opt = (struct opthdr *)(tor + 1); + opt->level = MIB2_IP; + opt->name = opt->len = 0; + + msg.maxlen = sizeof(buf); + msg.len = sizeof(*tor) + sizeof(*opt); + msg.buf = buf; + + if (putmsg(r->ip_fd, &msg, NULL, 0) < 0) + return (-1); + + opt = (struct opthdr *)(toa + 1); + msg.maxlen = sizeof(buf); + + for (;;) { + mib2_ipRouteEntry_t *rt, *rtend; + + flags = 0; + if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0) + return (-1); + + /* See if we're finished. */ + if (rc == 0 && + msg.len >= sizeof(*toa) && + toa->PRIM_type == T_OPTMGMT_ACK && + toa->MGMT_flags == T_SUCCESS && opt->len == 0) + break; + + if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK) + return (-1); + + if (rc != MOREDATA || msg.len < (int)sizeof(*toa) || + toa->PRIM_type != T_OPTMGMT_ACK || + toa->MGMT_flags != T_SUCCESS) + return (-1); + + rtable = (opt->level == MIB2_IP && opt->name == MIB2_IP_21); + + msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt)); + msg.len = 0; + flags = 0; + + do { + struct sockaddr_in sin; + + rc = getmsg(r->ip_fd, NULL, &msg, &flags); + + if (rc != 0 && rc != MOREDATA) + return (-1); + + if (!rtable) + continue; + + rt = (mib2_ipRouteEntry_t *)msg.buf; + rtend = (mib2_ipRouteEntry_t *)(msg.buf + msg.len); + + sin.sin_family = AF_INET; + + for ( ; rt < rtend; rt++) { + if ((rt->ipRouteInfo.re_ire_type & + (IRE_BROADCAST|IRE_ROUTE_REDIRECT| + IRE_LOCAL|IRE_ROUTE)) != 0 || + rt->ipRouteNextHop == IP_ADDR_ANY) + continue; + + entry.intf_name[0] = '\0'; + + sin.sin_addr.s_addr = rt->ipRouteNextHop; + addr_ston((struct sockaddr *)&sin, + &entry.route_gw); + + sin.sin_addr.s_addr = rt->ipRouteDest; + addr_ston((struct sockaddr *)&sin, + &entry.route_dst); + + sin.sin_addr.s_addr = rt->ipRouteMask; + addr_stob((struct sockaddr *)&sin, + &entry.route_dst.addr_bits); + + entry.metric = 0; + + if ((ret = callback(&entry, arg)) != 0) + return (ret); + } + } while (rc == MOREDATA); + } + + tor = (struct T_optmgmt_req *)buf; + toa = (struct T_optmgmt_ack *)buf; + tea = (struct T_error_ack *)buf; + + tor->PRIM_type = T_OPTMGMT_REQ; + tor->OPT_offset = sizeof(*tor); + tor->OPT_length = sizeof(*opt); + tor->MGMT_flags = T_CURRENT; + + opt = (struct opthdr *)(tor + 1); + opt->level = MIB2_IP6; + opt->name = opt->len = 0; + + msg.maxlen = sizeof(buf); + msg.len = sizeof(*tor) + sizeof(*opt); + msg.buf = buf; + + if (putmsg(r->ip_fd, &msg, NULL, 0) < 0) + return (-1); + + opt = (struct opthdr *)(toa + 1); + msg.maxlen = sizeof(buf); + + for (;;) { + mib2_ipv6RouteEntry_t *rt, *rtend; + + flags = 0; + if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0) + return (-1); + + /* See if we're finished. */ + if (rc == 0 && + msg.len >= sizeof(*toa) && + toa->PRIM_type == T_OPTMGMT_ACK && + toa->MGMT_flags == T_SUCCESS && opt->len == 0) + break; + + if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK) + return (-1); + + if (rc != MOREDATA || msg.len < (int)sizeof(*toa) || + toa->PRIM_type != T_OPTMGMT_ACK || + toa->MGMT_flags != T_SUCCESS) + return (-1); + + rtable = (opt->level == MIB2_IP6 && opt->name == MIB2_IP6_ROUTE); + + msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt)); + msg.len = 0; + flags = 0; + + do { + struct sockaddr_in6 sin6; + + rc = getmsg(r->ip_fd, NULL, &msg, &flags); + + if (rc != 0 && rc != MOREDATA) + return (-1); + + if (!rtable) + continue; + + rt = (mib2_ipv6RouteEntry_t *)msg.buf; + rtend = (mib2_ipv6RouteEntry_t *)(msg.buf + msg.len); + + sin6.sin6_family = AF_INET6; + + for ( ; rt < rtend; rt++) { + if ((rt->ipv6RouteInfo.re_ire_type & + (IRE_BROADCAST|IRE_ROUTE_REDIRECT| + IRE_LOCAL|IRE_ROUTE)) != 0 || + memcmp(&rt->ipv6RouteNextHop, IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0) + continue; + + entry.intf_name[0] = '\0'; + + sin6.sin6_addr = rt->ipv6RouteNextHop; + addr_ston((struct sockaddr *)&sin6, + &entry.route_gw); + + sin6.sin6_addr = rt->ipv6RouteDest; + addr_ston((struct sockaddr *)&sin6, + &entry.route_dst); + + entry.route_dst.addr_bits = rt->ipv6RoutePfxLength; + + if ((ret = callback(&entry, arg)) != 0) + return (ret); + } + } while (rc == MOREDATA); + } + return (0); +} +#elif defined(HAVE_NET_RADIX_H) +/* XXX - Tru64, others? */ +#include <nlist.h> + +static int +_kread(int fd, void *addr, void *buf, int len) +{ + if (lseek(fd, (off_t)addr, SEEK_SET) == (off_t)-1L) + return (-1); + return (read(fd, buf, len) == len ? 0 : -1); +} + +static int +_radix_walk(int fd, struct radix_node *rn, route_handler callback, void *arg) +{ + struct radix_node rnode; + struct rtentry rt; + struct sockaddr_in sin; + struct route_entry entry; + int ret = 0; + again: + _kread(fd, rn, &rnode, sizeof(rnode)); + if (rnode.rn_b < 0) { + if (!(rnode.rn_flags & RNF_ROOT)) { + entry.intf_name[0] = '\0'; + _kread(fd, rn, &rt, sizeof(rt)); + _kread(fd, rt_key(&rt), &sin, sizeof(sin)); + addr_ston((struct sockaddr *)&sin, &entry.route_dst); + if (!(rt.rt_flags & RTF_HOST)) { + _kread(fd, rt_mask(&rt), &sin, sizeof(sin)); + addr_stob((struct sockaddr *)&sin, + &entry.route_dst.addr_bits); + } + _kread(fd, rt.rt_gateway, &sin, sizeof(sin)); + addr_ston((struct sockaddr *)&sin, &entry.route_gw); + entry.metric = 0; + if ((ret = callback(&entry, arg)) != 0) + return (ret); + } + if ((rn = rnode.rn_dupedkey)) + goto again; + } else { + rn = rnode.rn_r; + if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0) + return (ret); + if ((ret = _radix_walk(fd, rn, callback, arg)) != 0) + return (ret); + } + return (ret); +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + struct radix_node_head *rnh, head; + struct nlist nl[2]; + int fd, ret = 0; + + memset(nl, 0, sizeof(nl)); + nl[0].n_name = "radix_node_head"; + + if (knlist(nl) < 0 || nl[0].n_type == 0 || + (fd = open("/dev/kmem", O_RDONLY, 0)) < 0) + return (-1); + + for (_kread(fd, (void *)nl[0].n_value, &rnh, sizeof(rnh)); + rnh != NULL; rnh = head.rnh_next) { + _kread(fd, rnh, &head, sizeof(head)); + /* XXX - only IPv4 for now... */ + if (head.rnh_af == AF_INET) { + if ((ret = _radix_walk(fd, head.rnh_treetop, + callback, arg)) != 0) + break; + } + } + close(fd); + return (ret); +} +#else +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} +#endif + +route_t * +route_close(route_t *r) +{ + if (r != NULL) { +#ifdef HAVE_STREAMS_MIB2 + if (r->ip_fd >= 0) + close(r->ip_fd); +#endif + if (r->fd >= 0) + close(r->fd); + free(r); + } + return (NULL); +} diff --git a/libdnet-stripped/src/route-hpux.c b/libdnet-stripped/src/route-hpux.c new file mode 100644 index 0000000..07e7f8c --- /dev/null +++ b/libdnet-stripped/src/route-hpux.c @@ -0,0 +1,184 @@ +/* + * route-hpux.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: route-hpux.c 483 2004-01-14 04:52:11Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/mib.h> +#include <sys/socket.h> + +#include <net/route.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +#define ADDR_ISHOST(a) (((a)->addr_type == ADDR_TYPE_IP && \ + (a)->addr_bits == IP_ADDR_BITS) || \ + ((a)->addr_type == ADDR_TYPE_IP6 && \ + (a)->addr_bits == IP6_ADDR_BITS)) + +struct route_handle { + int fd; +}; + +route_t * +route_open(void) +{ + route_t *r; + + if ((r = calloc(1, sizeof(*r))) != NULL) { + if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (route_close(r)); + } + return (r); +} + +int +route_add(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP | RTF_GATEWAY; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0 || + addr_btom(entry->route_dst.addr_bits, &rt.rt_subnetmask, + IP_ADDR_LEN) < 0) + return (-1); + + return (ioctl(r->fd, SIOCADDRT, &rt)); +} + +int +route_delete(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_btom(entry->route_dst.addr_bits, &rt.rt_subnetmask, + IP_ADDR_LEN) < 0) + return (-1); + + return (ioctl(r->fd, SIOCDELRT, &rt)); +} + +int +route_get(route_t *r, struct route_entry *entry) +{ + struct rtreq rtr; + + memset(&rtr, 0, sizeof(rtr)); + + /* XXX - gross hack for default route */ + if (entry->route_dst.addr_ip == IP_ADDR_ANY) { + rtr.rtr_destaddr = htonl(0x60060606); + rtr.rtr_subnetmask = 0xffffffff; + } else { + memcpy(&rtr.rtr_destaddr, &entry->route_dst.addr_ip, + IP_ADDR_LEN); + if (entry->route_dst.addr_bits < IP_ADDR_BITS) + addr_btom(entry->route_dst.addr_bits, + &rtr.rtr_subnetmask, IP_ADDR_LEN); + } + if (ioctl(r->fd, SIOCGRTENTRY, &rtr) < 0) + return (-1); + + if (rtr.rtr_gwayaddr == 0) { + errno = ESRCH; + return (-1); + } + entry->intf_name[0] = '\0'; + entry->route_gw.addr_type = ADDR_TYPE_IP; + entry->route_gw.addr_bits = IP_ADDR_BITS; + memcpy(&entry->route_gw.addr_ip, &rtr.rtr_gwayaddr, IP_ADDR_LEN); + entry->metric = 0; + + return (0); +} + +#define MAX_RTENTRIES 256 /* XXX */ + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + struct nmparms nm; + struct route_entry entry; + mib_ipRouteEnt rtentries[MAX_RTENTRIES]; + int fd, i, n, ret; + + if ((fd = open_mib("/dev/ip", O_RDWR, 0 /* XXX */, 0)) < 0) + return (-1); + + nm.objid = ID_ipRouteTable; + nm.buffer = rtentries; + n = sizeof(rtentries); + nm.len = &n; + + if (get_mib_info(fd, &nm) < 0) { + close_mib(fd); + return (-1); + } + close_mib(fd); + + n /= sizeof(*rtentries); + ret = 0; + + for (i = 0; i < n; i++) { + if (rtentries[i].Type != NMDIRECT && + rtentries[i].Type != NMREMOTE) + continue; + + entry.intf_name[0] = '\0'; + entry.route_dst.addr_type = entry.route_gw.addr_type = ADDR_TYPE_IP; + entry.route_dst.addr_bits = entry.route_gw.addr_bits = IP_ADDR_BITS; + entry.route_dst.addr_ip = rtentries[i].Dest; + addr_mtob(&rtentries[i].Mask, IP_ADDR_LEN, + &entry.route_dst.addr_bits); + entry.route_gw.addr_ip = rtentries[i].NextHop; + entry.metric = 0; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + return (ret); +} + +route_t * +route_close(route_t *r) +{ + if (r != NULL) { + if (r->fd >= 0) + close(r->fd); + free(r); + } + return (NULL); +} diff --git a/libdnet-stripped/src/route-linux.c b/libdnet-stripped/src/route-linux.c new file mode 100644 index 0000000..b14c527 --- /dev/null +++ b/libdnet-stripped/src/route-linux.c @@ -0,0 +1,310 @@ +/* + * route-linux.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: route-linux.c 619 2006-01-15 07:33:29Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <asm/types.h> +#include <net/if.h> +#include <netinet/in.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include <net/route.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +#define ADDR_ISHOST(a) (((a)->addr_type == ADDR_TYPE_IP && \ + (a)->addr_bits == IP_ADDR_BITS) || \ + ((a)->addr_type == ADDR_TYPE_IP6 && \ + (a)->addr_bits == IP6_ADDR_BITS)) + +#define PROC_ROUTE_FILE "/proc/net/route" +#define PROC_IPV6_ROUTE_FILE "/proc/net/ipv6_route" + +struct route_handle { + int fd; + int nlfd; +}; + +route_t * +route_open(void) +{ + struct sockaddr_nl snl; + route_t *r; + + if ((r = calloc(1, sizeof(*r))) != NULL) { + r->fd = r->nlfd = -1; + + if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (route_close(r)); + + if ((r->nlfd = socket(AF_NETLINK, SOCK_RAW, + NETLINK_ROUTE)) < 0) + return (route_close(r)); + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + if (bind(r->nlfd, (struct sockaddr *)&snl, sizeof(snl)) < 0) + return (route_close(r)); + } + return (r); +} + +int +route_add(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP | RTF_GATEWAY; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0 || + addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0) + return (-1); + + return (ioctl(r->fd, SIOCADDRT, &rt)); +} + +int +route_delete(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0) + return (-1); + + return (ioctl(r->fd, SIOCDELRT, &rt)); +} + +int +route_get(route_t *r, struct route_entry *entry) +{ + static int seq; + struct nlmsghdr *nmsg; + struct rtmsg *rmsg; + struct rtattr *rta; + struct sockaddr_nl snl; + struct iovec iov; + struct msghdr msg; + u_char buf[512]; + int i, af, alen; + + switch (entry->route_dst.addr_type) { + case ADDR_TYPE_IP: + af = AF_INET; + alen = IP_ADDR_LEN; + break; + case ADDR_TYPE_IP6: + af = AF_INET6; + alen = IP6_ADDR_LEN; + break; + default: + errno = EINVAL; + return (-1); + } + memset(buf, 0, sizeof(buf)); + + nmsg = (struct nlmsghdr *)buf; + nmsg->nlmsg_len = NLMSG_LENGTH(sizeof(*nmsg)) + RTA_LENGTH(alen); + nmsg->nlmsg_flags = NLM_F_REQUEST; + nmsg->nlmsg_type = RTM_GETROUTE; + nmsg->nlmsg_seq = ++seq; + + rmsg = (struct rtmsg *)(nmsg + 1); + rmsg->rtm_family = af; + rmsg->rtm_dst_len = entry->route_dst.addr_bits; + + rta = RTM_RTA(rmsg); + rta->rta_type = RTA_DST; + rta->rta_len = RTA_LENGTH(alen); + + /* XXX - gross hack for default route */ + if (af == AF_INET && entry->route_dst.addr_ip == IP_ADDR_ANY) { + i = htonl(0x60060606); + memcpy(RTA_DATA(rta), &i, alen); + } else + memcpy(RTA_DATA(rta), entry->route_dst.addr_data8, alen); + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + iov.iov_base = nmsg; + iov.iov_len = nmsg->nlmsg_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &snl; + msg.msg_namelen = sizeof(snl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (sendmsg(r->nlfd, &msg, 0) < 0) + return (-1); + + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + if ((i = recvmsg(r->nlfd, &msg, 0)) <= 0) + return (-1); + + if (nmsg->nlmsg_len < (int)sizeof(*nmsg) || nmsg->nlmsg_len > i || + nmsg->nlmsg_seq != seq) { + errno = EINVAL; + return (-1); + } + if (nmsg->nlmsg_type == NLMSG_ERROR) + return (-1); + + i -= NLMSG_LENGTH(sizeof(*nmsg)); + + entry->route_gw.addr_type = ADDR_TYPE_NONE; + entry->intf_name[0] = '\0'; + for (rta = RTM_RTA(rmsg); RTA_OK(rta, i); rta = RTA_NEXT(rta, i)) { + if (rta->rta_type == RTA_GATEWAY) { + entry->route_gw.addr_type = entry->route_dst.addr_type; + memcpy(entry->route_gw.addr_data8, RTA_DATA(rta), alen); + entry->route_gw.addr_bits = alen * 8; + } else if (rta->rta_type == RTA_OIF) { + char ifbuf[IFNAMSIZ]; + char *p; + int intf_index; + + intf_index = *(int *) RTA_DATA(rta); + p = if_indextoname(intf_index, ifbuf); + if (p == NULL) + return (-1); + strlcpy(entry->intf_name, ifbuf, sizeof(entry->intf_name)); + } + } + if (entry->route_gw.addr_type == ADDR_TYPE_NONE) { + errno = ESRCH; + return (-1); + } + + return (0); +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + FILE *fp; + struct route_entry entry; + char buf[BUFSIZ]; + char ifbuf[16]; + int ret = 0; + + if ((fp = fopen(PROC_ROUTE_FILE, "r")) != NULL) { + int i, iflags, refcnt, use, metric, mss, win, irtt; + uint32_t mask; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + i = sscanf(buf, "%15s %X %X %X %d %d %d %X %d %d %d\n", + ifbuf, &entry.route_dst.addr_ip, + &entry.route_gw.addr_ip, &iflags, &refcnt, &use, + &metric, &mask, &mss, &win, &irtt); + + if (i < 11 || !(iflags & RTF_UP)) + continue; + + strlcpy(entry.intf_name, ifbuf, sizeof(entry.intf_name)); + + entry.route_dst.addr_type = entry.route_gw.addr_type = + ADDR_TYPE_IP; + + if (addr_mtob(&mask, IP_ADDR_LEN, + &entry.route_dst.addr_bits) < 0) + continue; + + entry.route_gw.addr_bits = IP_ADDR_BITS; + entry.metric = metric; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + fclose(fp); + } + if (ret == 0 && (fp = fopen(PROC_IPV6_ROUTE_FILE, "r")) != NULL) { + char s[33], d[8][5], n[8][5]; + int i, iflags, metric; + u_int slen, dlen; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + i = sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %02x " + "%32s %02x %04s%04s%04s%04s%04s%04s%04s%04s " + "%x %*x %*x %x %15s", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + &dlen, s, &slen, + n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], + &metric, &iflags, ifbuf); + + if (i < 21 || !(iflags & RTF_UP)) + continue; + + strlcpy(entry.intf_name, ifbuf, sizeof(entry.intf_name)); + + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + dlen); + addr_aton(buf, &entry.route_dst); + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", + n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], + IP6_ADDR_BITS); + addr_aton(buf, &entry.route_gw); + entry.metric = metric; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + fclose(fp); + } + return (ret); +} + +route_t * +route_close(route_t *r) +{ + if (r != NULL) { + if (r->fd >= 0) + close(r->fd); + if (r->nlfd >= 0) + close(r->nlfd); + free(r); + } + return (NULL); +} diff --git a/libdnet-stripped/src/route-none.c b/libdnet-stripped/src/route-none.c new file mode 100644 index 0000000..bbe2216 --- /dev/null +++ b/libdnet-stripped/src/route-none.c @@ -0,0 +1,58 @@ +/* + * route-none.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: route-none.c 260 2002-02-04 04:03:45Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +route_t * +route_open(void) +{ + errno = ENOSYS; + return (NULL); +} + +int +route_add(route_t *r, const struct route_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +route_delete(route_t *r, const struct route_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +route_get(route_t *r, struct route_entry *entry) +{ + errno = ENOSYS; + return (-1); +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} + +route_t * +route_close(route_t *r) +{ + return (NULL); +} diff --git a/libdnet-stripped/src/route-win32.c b/libdnet-stripped/src/route-win32.c new file mode 100644 index 0000000..8a9d2bc --- /dev/null +++ b/libdnet-stripped/src/route-win32.c @@ -0,0 +1,279 @@ +/* + * route-win32.c + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: route-win32.c 589 2005-02-15 07:11:32Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include <ws2tcpip.h> +#include <iphlpapi.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "dnet.h" + +typedef DWORD (WINAPI *GETIPFORWARDTABLE2)(ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2 *); + +struct route_handle { + HINSTANCE iphlpapi; + MIB_IPFORWARDTABLE *ipftable; + MIB_IPFORWARD_TABLE2 *ipftable2; +}; + +route_t * +route_open(void) +{ + route_t *r; + + r = calloc(1, sizeof(route_t)); + if (r == NULL) + return NULL; + r->iphlpapi = GetModuleHandle("iphlpapi.dll"); + + return r; +} + +int +route_add(route_t *route, const struct route_entry *entry) +{ + MIB_IPFORWARDROW ipfrow; + struct addr net; + + memset(&ipfrow, 0, sizeof(ipfrow)); + + if (GetBestInterface(entry->route_gw.addr_ip, + &ipfrow.dwForwardIfIndex) != NO_ERROR) + return (-1); + + if (addr_net(&entry->route_dst, &net) < 0 || + net.addr_type != ADDR_TYPE_IP) + return (-1); + + ipfrow.dwForwardDest = net.addr_ip; + addr_btom(entry->route_dst.addr_bits, + &ipfrow.dwForwardMask, IP_ADDR_LEN); + ipfrow.dwForwardNextHop = entry->route_gw.addr_ip; + ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */ + ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */ + + if (CreateIpForwardEntry(&ipfrow) != NO_ERROR) + return (-1); + + return (0); +} + +int +route_delete(route_t *route, const struct route_entry *entry) +{ + MIB_IPFORWARDROW ipfrow; + DWORD mask; + + if (entry->route_dst.addr_type != ADDR_TYPE_IP || + GetBestRoute(entry->route_dst.addr_ip, + IP_ADDR_ANY, &ipfrow) != NO_ERROR) + return (-1); + + addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN); + + if (ipfrow.dwForwardDest != entry->route_dst.addr_ip || + ipfrow.dwForwardMask != mask) { + errno = ENXIO; + SetLastError(ERROR_NO_DATA); + return (-1); + } + if (DeleteIpForwardEntry(&ipfrow) != NO_ERROR) + return (-1); + + return (0); +} + +int +route_get(route_t *route, struct route_entry *entry) +{ + MIB_IPFORWARDROW ipfrow; + DWORD mask; + intf_t *intf; + struct intf_entry intf_entry; + + if (entry->route_dst.addr_type != ADDR_TYPE_IP || + GetBestRoute(entry->route_dst.addr_ip, + IP_ADDR_ANY, &ipfrow) != NO_ERROR) + return (-1); + + if (ipfrow.dwForwardProto == 2 && /* XXX - MIB_IPPROTO_LOCAL */ + (ipfrow.dwForwardNextHop|IP_CLASSA_NET) != + (IP_ADDR_LOOPBACK|IP_CLASSA_NET) && + !IP_LOCAL_GROUP(ipfrow.dwForwardNextHop)) { + errno = ENXIO; + SetLastError(ERROR_NO_DATA); + return (-1); + } + addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN); + + entry->route_gw.addr_type = ADDR_TYPE_IP; + entry->route_gw.addr_bits = IP_ADDR_BITS; + entry->route_gw.addr_ip = ipfrow.dwForwardNextHop; + entry->metric = ipfrow.dwForwardMetric1; + + entry->intf_name[0] = '\0'; + intf = intf_open(); + if (intf_get_index(intf, &intf_entry, + AF_INET, ipfrow.dwForwardIfIndex) == 0) { + strlcpy(entry->intf_name, intf_entry.intf_name, sizeof(entry->intf_name)); + } + intf_close(intf); + + return (0); +} + +static int +route_loop_getipforwardtable(route_t *r, route_handler callback, void *arg) +{ + struct route_entry entry; + intf_t *intf; + ULONG len; + int i, ret; + + for (len = sizeof(r->ipftable[0]); ; ) { + if (r->ipftable) + free(r->ipftable); + r->ipftable = malloc(len); + if (r->ipftable == NULL) + return (-1); + ret = GetIpForwardTable(r->ipftable, &len, FALSE); + if (ret == NO_ERROR) + break; + else if (ret != ERROR_INSUFFICIENT_BUFFER) + return (-1); + } + + intf = intf_open(); + + ret = 0; + for (i = 0; i < (int)r->ipftable->dwNumEntries; i++) { + struct intf_entry intf_entry; + + entry.route_dst.addr_type = ADDR_TYPE_IP; + entry.route_dst.addr_bits = IP_ADDR_BITS; + + entry.route_gw.addr_type = ADDR_TYPE_IP; + entry.route_gw.addr_bits = IP_ADDR_BITS; + + entry.route_dst.addr_ip = r->ipftable->table[i].dwForwardDest; + addr_mtob(&r->ipftable->table[i].dwForwardMask, IP_ADDR_LEN, + &entry.route_dst.addr_bits); + entry.route_gw.addr_ip = + r->ipftable->table[i].dwForwardNextHop; + entry.metric = r->ipftable->table[i].dwForwardMetric1; + + /* Look up the interface name. */ + entry.intf_name[0] = '\0'; + intf_entry.intf_len = sizeof(intf_entry); + if (intf_get_index(intf, &intf_entry, + AF_INET, r->ipftable->table[i].dwForwardIfIndex) == 0) { + strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name)); + } + + if ((ret = (*callback)(&entry, arg)) != 0) + break; + } + + intf_close(intf); + + return ret; +} + +static int +route_loop_getipforwardtable2(GETIPFORWARDTABLE2 GetIpForwardTable2, + route_t *r, route_handler callback, void *arg) +{ + struct route_entry entry; + intf_t *intf; + ULONG i; + int ret; + + ret = GetIpForwardTable2(AF_UNSPEC, &r->ipftable2); + if (ret != NO_ERROR) + return (-1); + + intf = intf_open(); + + ret = 0; + for (i = 0; i < r->ipftable2->NumEntries; i++) { + struct intf_entry intf_entry; + MIB_IPFORWARD_ROW2 *row; + MIB_IPINTERFACE_ROW ifrow; + ULONG metric; + + row = &r->ipftable2->Table[i]; + addr_ston((struct sockaddr *) &row->DestinationPrefix.Prefix, &entry.route_dst); + entry.route_dst.addr_bits = row->DestinationPrefix.PrefixLength; + addr_ston((struct sockaddr *) &row->NextHop, &entry.route_gw); + + /* Look up the interface name. */ + entry.intf_name[0] = '\0'; + intf_entry.intf_len = sizeof(intf_entry); + if (intf_get_index(intf, &intf_entry, + row->DestinationPrefix.Prefix.si_family, + row->InterfaceIndex) == 0) { + strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name)); + } + + ifrow.Family = row->DestinationPrefix.Prefix.si_family; + ifrow.InterfaceLuid = row->InterfaceLuid; + ifrow.InterfaceIndex = row->InterfaceIndex; + if (GetIpInterfaceEntry(&ifrow) != NO_ERROR) { + return (-1); + } + metric = ifrow.Metric + row->Metric; + if (metric < INT_MAX) + entry.metric = metric; + else + entry.metric = INT_MAX; + + if ((ret = (*callback)(&entry, arg)) != 0) + break; + } + + intf_close(intf); + + return ret; +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + GETIPFORWARDTABLE2 GetIpForwardTable2; + + /* GetIpForwardTable2 is only available on Vista and later, dynamic load. */ + GetIpForwardTable2 = NULL; + if (r->iphlpapi != NULL) + GetIpForwardTable2 = (GETIPFORWARDTABLE2) GetProcAddress(r->iphlpapi, "GetIpForwardTable2"); + + if (GetIpForwardTable2 == NULL) + return route_loop_getipforwardtable(r, callback, arg); + else + return route_loop_getipforwardtable2(GetIpForwardTable2, r, callback, arg); +} + +route_t * +route_close(route_t *r) +{ + if (r != NULL) { + if (r->ipftable != NULL) + free(r->ipftable); + if (r->ipftable2 != NULL) + FreeMibTable(r->ipftable2); + free(r); + } + return (NULL); +} diff --git a/libdnet-stripped/src/strlcpy.c b/libdnet-stripped/src/strlcpy.c new file mode 100644 index 0000000..5f58696 --- /dev/null +++ b/libdnet-stripped/src/strlcpy.c @@ -0,0 +1,69 @@ +/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/libdnet-stripped/src/strsep.c b/libdnet-stripped/src/strsep.c new file mode 100644 index 0000000..b69b715 --- /dev/null +++ b/libdnet-stripped/src/strsep.c @@ -0,0 +1,85 @@ +/* $OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 <string.h> +#include <stdio.h> + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#else +static char *rcsid = "$OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(stringp, delim) + register char **stringp; + register const char *delim; +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/libdnet-stripped/src/tun-bsd.c b/libdnet-stripped/src/tun-bsd.c new file mode 100644 index 0000000..293abc8 --- /dev/null +++ b/libdnet-stripped/src/tun-bsd.c @@ -0,0 +1,146 @@ +/* + * tun-bsd.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: tun-bsd.c 573 2005-02-10 23:50:04Z dugsong $ + */ + +#include "config.h" + +#include <sys/socket.h> +#include <sys/uio.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct tun { + int fd; + intf_t *intf; + struct intf_entry save; +}; + +#define MAX_DEVS 16 /* XXX - max number of tunnel devices */ + +tun_t * +tun_open(struct addr *src, struct addr *dst, int mtu) +{ + struct intf_entry ifent; + tun_t *tun; + char dev[128]; + int i; + + if (src->addr_type != ADDR_TYPE_IP || dst->addr_type != ADDR_TYPE_IP || + src->addr_bits != IP_ADDR_BITS || dst->addr_bits != IP_ADDR_BITS) { + errno = EINVAL; + return (NULL); + } + if ((tun = calloc(1, sizeof(*tun))) == NULL) + return (NULL); + + if ((tun->intf = intf_open()) == NULL) + return (tun_close(tun)); + + memset(&ifent, 0, sizeof(ifent)); + ifent.intf_len = sizeof(ifent); + + for (i = 0; i < MAX_DEVS; i++) { + snprintf(dev, sizeof(dev), "/dev/tun%d", i); + strlcpy(ifent.intf_name, dev + 5, sizeof(ifent.intf_name)); + tun->save = ifent; + + if ((tun->fd = open(dev, O_RDWR, 0)) != -1 && + intf_get(tun->intf, &tun->save) == 0) { + route_t *r; + struct route_entry entry; + + ifent.intf_flags = INTF_FLAG_UP|INTF_FLAG_POINTOPOINT; + ifent.intf_addr = *src; + ifent.intf_dst_addr = *dst; + ifent.intf_mtu = mtu; + + if (intf_set(tun->intf, &ifent) < 0) + tun = tun_close(tun); + + /* XXX - try to ensure our route got set */ + if ((r = route_open()) != NULL) { + entry.route_dst = *dst; + entry.route_gw = *src; + route_add(r, &entry); + route_close(r); + } + break; + } + } + if (i == MAX_DEVS) + tun = tun_close(tun); + return (tun); +} + +const char * +tun_name(tun_t *tun) +{ + return (tun->save.intf_name); +} + +int +tun_fileno(tun_t *tun) +{ + return (tun->fd); +} + +ssize_t +tun_send(tun_t *tun, const void *buf, size_t size) +{ +#ifdef __OpenBSD__ + struct iovec iov[2]; + uint32_t af = htonl(AF_INET); + + iov[0].iov_base = ⁡ + iov[0].iov_len = sizeof(af); + iov[1].iov_base = (void *)buf; + iov[1].iov_len = size; + + return (writev(tun->fd, iov, 2)); +#else + return (write(tun->fd, buf, size)); +#endif +} + +ssize_t +tun_recv(tun_t *tun, void *buf, size_t size) +{ +#ifdef __OpenBSD__ + struct iovec iov[2]; + uint32_t af; + + iov[0].iov_base = ⁡ + iov[0].iov_len = sizeof(af); + iov[1].iov_base = (void *)buf; + iov[1].iov_len = size; + + return (readv(tun->fd, iov, 2) - sizeof(af)); +#else + return (read(tun->fd, buf, size)); +#endif +} + +tun_t * +tun_close(tun_t *tun) +{ + if (tun->fd > 0) + close(tun->fd); + if (tun->intf != NULL) { + /* Restore interface configuration on close. */ + intf_set(tun->intf, &tun->save); + intf_close(tun->intf); + } + free(tun); + return (NULL); +} diff --git a/libdnet-stripped/src/tun-linux.c b/libdnet-stripped/src/tun-linux.c new file mode 100644 index 0000000..38fe0b4 --- /dev/null +++ b/libdnet-stripped/src/tun-linux.c @@ -0,0 +1,115 @@ +/* + * tun-linux.c + * + * Universal TUN/TAP driver, in Linux 2.4+ + * /usr/src/linux/Documentation/networking/tuntap.txt + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: tun-linux.c 612 2005-09-12 02:18:06Z dugsong $ + */ + +#include "config.h" + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <linux/if.h> +#include <linux/if_tun.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct tun { + int fd; + intf_t *intf; + struct ifreq ifr; +}; + +tun_t * +tun_open(struct addr *src, struct addr *dst, int mtu) +{ + tun_t *tun; + struct intf_entry ifent; + + if ((tun = calloc(1, sizeof(*tun))) == NULL) + return (NULL); + + if ((tun->fd = open("/dev/net/tun", O_RDWR, 0)) < 0 || + (tun->intf = intf_open()) == NULL) + return (tun_close(tun)); + + tun->ifr.ifr_flags = IFF_TUN; + + if (ioctl(tun->fd, TUNSETIFF, (void *) &tun->ifr) < 0) + return (tun_close(tun)); + + memset(&ifent, 0, sizeof(ifent)); + strlcpy(ifent.intf_name, tun->ifr.ifr_name, sizeof(ifent.intf_name)); + ifent.intf_flags = INTF_FLAG_UP|INTF_FLAG_POINTOPOINT; + ifent.intf_addr = *src; + ifent.intf_dst_addr = *dst; + ifent.intf_mtu = mtu; + + if (intf_set(tun->intf, &ifent) < 0) + return (tun_close(tun)); + + return (tun); +} + +const char * +tun_name(tun_t *tun) +{ + return (tun->ifr.ifr_name); +} + +int +tun_fileno(tun_t *tun) +{ + return (tun->fd); +} + +ssize_t +tun_send(tun_t *tun, const void *buf, size_t size) +{ + struct iovec iov[2]; + uint32_t type = ETH_TYPE_IP; + + iov[0].iov_base = &type; + iov[0].iov_len = sizeof(type); + iov[1].iov_base = (void *)buf; + iov[1].iov_len = size; + + return (writev(tun->fd, iov, 2)); +} + +ssize_t +tun_recv(tun_t *tun, void *buf, size_t size) +{ + struct iovec iov[2]; + uint32_t type; + + iov[0].iov_base = &type; + iov[0].iov_len = sizeof(type); + iov[1].iov_base = (void *)buf; + iov[1].iov_len = size; + + return (readv(tun->fd, iov, 2) - sizeof(type)); +} + +tun_t * +tun_close(tun_t *tun) +{ + if (tun->fd > 0) + close(tun->fd); + if (tun->intf != NULL) + intf_close(tun->intf); + free(tun); + return (NULL); +} diff --git a/libdnet-stripped/src/tun-none.c b/libdnet-stripped/src/tun-none.c new file mode 100644 index 0000000..940d8ae --- /dev/null +++ b/libdnet-stripped/src/tun-none.c @@ -0,0 +1,58 @@ +/* + * tun-none.c + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: tun-none.c 548 2005-01-30 06:01:57Z dugsong $ + */ + +#include "config.h" + +#include <sys/types.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "dnet.h" + +tun_t * +tun_open(struct addr *src, struct addr *dst, int mtu) +{ + errno = ENOSYS; + return (NULL); +} + +const char * +tun_name(tun_t *tun) +{ + errno = ENOSYS; + return (NULL); +} + +int +tun_fileno(tun_t *tun) +{ + errno = ENOSYS; + return (-1); +} + +ssize_t +tun_send(tun_t *tun, const void *buf, size_t size) +{ + errno = ENOSYS; + return (-1); +} + +ssize_t +tun_recv(tun_t *tun, void *buf, size_t size) +{ + errno = ENOSYS; + return (-1); +} + +tun_t * +tun_close(tun_t *tun) +{ + return (NULL); +} diff --git a/libdnet-stripped/src/tun-solaris.c b/libdnet-stripped/src/tun-solaris.c new file mode 100644 index 0000000..07186ce --- /dev/null +++ b/libdnet-stripped/src/tun-solaris.c @@ -0,0 +1,127 @@ +/* + * tun-solaris.c + * + * Universal TUN/TAP driver + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: tun-solaris.c 547 2005-01-25 21:30:40Z dugsong $ + */ + +#include "config.h" + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <net/if.h> +#include <net/if_tun.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stropts.h> +#include <unistd.h> + +#include "dnet.h" + +#define DEV_TUN "/dev/tun" +#define DEV_IP "/dev/ip" + +struct tun { + int fd; + int ip_fd; + int if_fd; + char name[16]; +}; + +tun_t * +tun_open(struct addr *src, struct addr *dst, int mtu) +{ + tun_t *tun; + char cmd[512]; + int ppa; + + if ((tun = calloc(1, sizeof(*tun))) == NULL) + return (NULL); + + tun->fd = tun->ip_fd = tun->if_fd = -1; + + if ((tun->fd = open(DEV_TUN, O_RDWR, 0)) < 0) + return (tun_close(tun)); + + if ((tun->ip_fd = open(DEV_IP, O_RDWR, 0)) < 0) + return (tun_close(tun)); + + if ((ppa = ioctl(tun->fd, TUNNEWPPA, ppa)) < 0) + return (tun_close(tun)); + + if ((tun->if_fd = open(DEV_TUN, O_RDWR, 0)) < 0) + return (tun_close(tun)); + + if (ioctl(tun->if_fd, I_PUSH, "ip") < 0) + return (tun_close(tun)); + + if (ioctl(tun->if_fd, IF_UNITSEL, (char *)&ppa) < 0) + return (tun_close(tun)); + + if (ioctl(tun->ip_fd, I_LINK, tun->if_fd) < 0) + return (tun_close(tun)); + + snprintf(tun->name, sizeof(tun->name), "tun%d", ppa); + + snprintf(cmd, sizeof(cmd), "ifconfig %s %s/32 %s mtu %d up", + tun->name, addr_ntoa(src), addr_ntoa(dst), mtu); + + if (system(cmd) < 0) + return (tun_close(tun)); + + return (tun); +} + +const char * +tun_name(tun_t *tun) +{ + return (tun->name); +} + +int +tun_fileno(tun_t *tun) +{ + return (tun->fd); +} + +ssize_t +tun_send(tun_t *tun, const void *buf, size_t size) +{ + struct strbuf sbuf; + + sbuf.buf = buf; + sbuf.len = size; + return (putmsg(tun->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1); +} + +ssize_t +tun_recv(tun_t *tun, void *buf, size_t size) +{ + struct strbuf sbuf; + int flags = 0; + + sbuf.buf = buf; + sbuf.maxlen = size; + return (getmsg(tun->fd, NULL, &sbuf, &flags) >= 0 ? sbuf.len : -1); +} + +tun_t * +tun_close(tun_t *tun) +{ + if (tun->if_fd >= 0) + close(tun->if_fd); + if (tun->ip_fd >= 0) + close(tun->ip_fd); + if (tun->fd >= 0) + close(tun->fd); + free(tun); + return (NULL); +} |