├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── bin └── .gitignore ├── doc ├── high-level-design.pptx └── robdns-0.2-manual.docx ├── examples ├── example.zone ├── keys.conf └── master.conf ├── src ├── adapter-pcapfile.c ├── adapter-pcapfile.h ├── adapter-pcaplive.c ├── adapter-pcaplive.h ├── adapter-recv.c ├── adapter-xmit.c ├── adapter.c ├── adapter.h ├── conf-addrlist.c ├── conf-addrlist.h ├── conf-error.h ├── conf-keys.c ├── conf-keys.h ├── conf-load-options.c ├── conf-load.c ├── conf-load.h ├── conf-options.h ├── conf-parse.c ├── conf-parse.h ├── conf-selftest.c ├── conf-trackfile.c ├── conf-trackfile.h ├── conf-zone.c ├── conf-zone.h ├── conf-zonedir.c ├── configuration-adapter.h ├── configuration.c ├── configuration.h ├── crypto-base64.c ├── crypto-base64.h ├── crypto-md5.c ├── crypto-md5.h ├── crypto-murmur3.c ├── crypto-murmur3.h ├── crypto-siphash.c ├── crypto-siphash.h ├── db-catalog.c ├── db-entry.c ├── db-entry.h ├── db-rrset.h ├── db-xdomain.c ├── db-xdomain.h ├── db-zone.c ├── db-zone.h ├── db.h ├── domainname.h ├── extract.h ├── grind-config.c ├── grind.c ├── grind.h ├── logger.c ├── logger.h ├── logging.h ├── main-checkconf.c ├── main-checkzone.c ├── main-conf.c ├── main-conf.h ├── main-listif.c ├── main-pcap2zone.c ├── main-regression.c ├── main-regression.h ├── main-server-socket.c ├── main-server-socket.h ├── main-server.c ├── main-thread.c ├── main-thread.h ├── main.c ├── network.h ├── packet.h ├── perftest.c ├── pixie-atomic.h ├── pixie-nic.c ├── pixie-nic.h ├── pixie-sockets.h ├── pixie-threads.c ├── pixie-threads.h ├── pixie-timer.c ├── pixie-timer.h ├── pixie.c ├── pixie.h ├── proto-arp.c ├── proto-dns-compressor.c ├── proto-dns-compressor.h ├── proto-dns-formatter.c ├── proto-dns-formatter.h ├── proto-dns-parse.c ├── proto-dns.h ├── proto-icmp.c ├── proto-ip.c ├── proto-preprocess.c ├── proto-preprocess.h ├── proto-udp.c ├── rawsock-pfring.c ├── rawsock-pfring.h ├── rawsock.c ├── rawsock.h ├── resolver.c ├── resolver.h ├── robdns.h ├── rte-ring.c ├── rte-ring.h ├── selftest-parsefast.c ├── selftest.c ├── selftest.h ├── smack.h ├── smack1.c ├── smackqueue.c ├── smackqueue.h ├── source.h ├── string_s.c ├── string_s.h ├── success-failure.h ├── thread-atomic.h ├── thread-worker.c ├── thread.h ├── unusedparm.h ├── util-filename.c ├── util-filename.h ├── util-ipaddr.c ├── util-ipaddr.h ├── util-keyword.c ├── util-keyword.h ├── util-ranges.c ├── util-ranges.h ├── util-realloc2.c ├── util-realloc2.h ├── zonefile-dfa.c ├── zonefile-dfa.h ├── zonefile-field-charstring.c ├── zonefile-field-loc.c ├── zonefile-fields.c ├── zonefile-fields.h ├── zonefile-insertion.c ├── zonefile-insertion.h ├── zonefile-load.c ├── zonefile-load.h ├── zonefile-parse.c ├── zonefile-parse.h ├── zonefile-print.c ├── zonefile-rr.c ├── zonefile-rr.h └── zonefile-tracker.h ├── tmp └── .gitignore ├── vs10 ├── .gitignore ├── robdns.sln ├── robdns.vcxproj └── robdns.vcxproj.filters └── xcode4 └── robdns.xcodeproj ├── .gitignore └── project.pbxproj /.gitignore: -------------------------------------------------------------------------------- 1 | self-query.pcap 2 | .DS_Store 3 | self-response.pcap 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # This is a build/test script for "travis-ci", a continuous 2 | # integration website that will build and test this project 3 | # every time something is submitted, and send me email if 4 | # the test breaks 5 | language: c 6 | compiler: 7 | - gcc 8 | - clang 9 | before_install: 10 | - sudo apt-get install -y libpcap-dev 11 | script: make && make test 12 | 13 | 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | SYS := $(shell gcc -dumpmachine) 4 | 5 | # LINUX 6 | # The automated regression tests run on Linux, so this is the one 7 | # environment where things likely will work -- as well as anything 8 | # works on the bajillion of different Linux environments 9 | ifneq (, $(findstring linux, $(SYS))) 10 | LIBS = -lpcap -lm -lrt -ldl -rdynamic -lpthread 11 | INCLUDES = -I. 12 | FLAGS2 = 13 | endif 14 | 15 | # MAC OS X 16 | # I occassionally develope code on Mac OS X, but it's not part of 17 | # my regularly regression-test environment. That means at any point 18 | # in time, something might be minorly broken in Mac OS X. 19 | ifneq (, $(findstring darwin, $(SYS))) 20 | LIBS = -lpcap -lm 21 | INCLUDES = 22 | FLAGS2 = 23 | endif 24 | 25 | # MinGW on Windows 26 | # I develope on Visual Studio 2010, so that's the Windows environment 27 | # that'll work. However, 'git' on Windows runs under MingGW, so one 28 | # day I acccidentally typed 'make' instead of 'git, and felt compelled 29 | # to then fix all the errors, so this kinda works now. It's not the 30 | # intended environment, so it make break in the future. 31 | ifneq (, $(findstring mingw, $(SYS))) 32 | INCLUDES = -Ivs10/include 33 | LIBS = -lIPHLPAPI -lWs2_32 34 | FLAGS2 = -march=i686 35 | endif 36 | 37 | # Cygwin 38 | # I hate Cygwin, use Visual Studio or MingGW instead. I just put this 39 | # second here for completeness, or in case I gate tired of hitting my 40 | # head with a hammer and want to feel a different sort of pain. 41 | ifneq (, $(findstring cygwin, $(SYS))) 42 | INCLUDES = -I. 43 | LIBS = -lwpcap 44 | FLAGS2 = 45 | endif 46 | 47 | # OpenBSD 48 | ifneq (, $(findstring openbsd, $(SYS))) 49 | LIBS = -lpcap -lm -pthread 50 | INCLUDES = -I. 51 | FLAGS2 = 52 | endif 53 | 54 | # this works on llvm or real gcc 55 | CC = gcc 56 | 57 | DEFINES = 58 | CFLAGS = -g $(FLAGS2) $(INCLUDES) $(DEFINES) -Wall -O3 59 | .SUFFIXES: .c .cpp 60 | 61 | # just compile everything in the 'src' directory. Using this technique 62 | # means that include file dependencies are broken, so sometimes when 63 | # the program crashes unexpectedly, 'make clean' then 'make' fixes the 64 | # problem that a .h file was out of date 65 | tmp/%.o: src/%.c 66 | $(CC) $(CFLAGS) -c $< -o $@ 67 | 68 | SRC = $(wildcard src/*.c) 69 | OBJ = $(addprefix tmp/, $(notdir $(addsuffix .o, $(basename $(SRC))))) 70 | 71 | bin/robdns: $(OBJ) 72 | $(CC) $(CFLAGS) -o $@ $(OBJ) $(LIBS) 73 | 74 | clean: 75 | rm tmp/*.o 76 | rm bin/robdns 77 | 78 | regress: bin/robdns 79 | bin/robdns --selftest 80 | 81 | test: regress 82 | 83 | 84 | install: bin/robdns 85 | echo "No install, binary is bin/robdns" 86 | 87 | default: bin/robdns 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # robdns: infrastructure DNS server 2 | 3 | This is a fast super-slave DNS server, designed to be constantly attacked 4 | on the public Internet. The intent is to shield master servers that are 5 | hidden behind firewalls. The key feature is a built-in custom TCP/IP stack 6 | capable of handling millions of DNS queries-per-second per CPU core. 7 | 8 | Currently, this tool is in a prototype stage. It parses records and 9 | responds to queries on port 53, but it's missing key features such 10 | as dynamic updates. 11 | 12 | 13 | # Building 14 | 15 | The only dependency is `libpcap-dev` (or `WinPcap`). 16 | 17 | Just type `make` to build the software on Linux, Mac OS X, and Windows 18 | (MinGW). 19 | 20 | The included XCode4 and VS10 projects should also work on Mac and 21 | Windows respectively. 22 | 23 | 24 | # Running 25 | 26 | The easiest way to test the server is to run on the comman-line with one 27 | or more DNS zone-files, like so: 28 | 29 | # robdns example.zone 30 | 31 | This will start listening on the `any` IP address (v4 and v6) on port 53. 32 | Zone-files are in the standard format, with a filename ending in `.zone`, 33 | and starting with an SOA record. 34 | 35 | To test that it's running, you can use the normal `dig` command. 36 | 37 | $ dig chaos txt version.bind @localhost +short 38 | 39 | You should get back the version string of `robdns/1`. 40 | 41 | 42 | However, the above example is the **slow** way of running the software. 43 | The intended use is to bypass the kernel's network stack using special 44 | drivers like PF_RING. To run in this faster mode, install the drivers 45 | and run with a command like the following: 46 | 47 | # robdns example.zone dna0 192.168.1.222 48 | 49 | In this example, the server will use it's own user-mode TCP/IP stack 50 | instead. Currently, this benchmarks to about 1-million packets-per-second 51 | for each CPU core. 52 | 53 | 54 | # Feature status 55 | 56 | The following RR types have been implemented: 57 | 58 | SOA, NS, 59 | A, AAAA, PTR, CNAME, 60 | SSHFP, LOC, TXT, SRV, SPF, HINFO, MX, 61 | DNSKEY, NSEC, NSEC3, NSEC3PARAM, RRSIG, DS, TLSA, 62 | EDNS0, 63 | 64 | 65 | The following interfaces are supported: 66 | sockets, libpcap, PF_RING 67 | 68 | 69 | 70 | # Authors 71 | 72 | This tool created by Robert Graham: 73 | email: robert_david_graham@yahoo.com 74 | twitter: @ErrataRob 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | 4 | 5 | -------------------------------------------------------------------------------- /doc/high-level-design.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertdavidgraham/robdns/d76d2e6817ebefe240c667aecdc478d7e3fec586/doc/high-level-design.pptx -------------------------------------------------------------------------------- /doc/robdns-0.2-manual.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertdavidgraham/robdns/d76d2e6817ebefe240c667aecdc478d7e3fec586/doc/robdns-0.2-manual.docx -------------------------------------------------------------------------------- /examples/example.zone: -------------------------------------------------------------------------------- 1 | $TTL 86400 ; 24 hours could have been written as 24h or 1d 2 | $ORIGIN example.com. 3 | @ 1D IN SOA ns1.example.com. hostmaster.example.com. ( 4 | 2002022401 ; serial 5 | 3H ; refresh 6 | 15 ; retry 7 | 1w ; expire 8 | 3h ; minimum 9 | ) 10 | IN NS ns1.example.com. ; in the domain 11 | IN NS ns2.smokeyjoe.com. ; external to domain 12 | IN MX 10 mail.another.com. ; external mail provider 13 | ; server host definitions 14 | ns1 IN A 192.168.0.1 ;name server definition 15 | www IN A 192.168.0.2 ;web server definition 16 | ftp IN CNAME www.example.com. ;ftp server definition 17 | ; non server domain hosts 18 | bill IN A 192.168.0.3 19 | fred IN A 192.168.0.4 20 | foo A 1.2.3.4 21 | -------------------------------------------------------------------------------- /examples/keys.conf: -------------------------------------------------------------------------------- 1 | /* 2 | This is "key" file that specifies the keys that servers use 3 | to talk to each other. Both servers must know the same key. 4 | Typically, keys are stored in separate files with increased 5 | security so that only administrators can see them. Other 6 | people can see the rest of DNS server configurations, and 7 | zone administrators can typically write to zonefiles. 8 | */ 9 | 10 | key "example-key" { 11 | algorithm hmac-md5; 12 | secret "7zTrFAk8z5YP2IaHNdy0ig=="; 13 | }; 14 | -------------------------------------------------------------------------------- /examples/master.conf: -------------------------------------------------------------------------------- 1 | /* 2 | This is the configuration for a "master" zone. This zone 3 | receives updates only through changes to the zonefiles. 4 | This can be done by editing them with a text editor, 5 | using scripts to extract information from other sources 6 | like databases, or using a tool like rsync to keep them 7 | up-to-date with another server somewhere. Dynamic updates 8 | through AXFR/IXFR and UPDATE are not possible. 9 | */ 10 | 11 | include "keys.conf"; 12 | 13 | 14 | zone "example.com" { 15 | // This is a master, not a slave 16 | type master; 17 | 18 | // The file containing the information for this zone is 19 | // located here. 20 | file "example.zone"; 21 | 22 | // Zone transfers (AXFR and IXFR) can be initiated from 23 | // anybody who knows the right key, or from anybody on 24 | // the local system. 25 | allow-transfer { 26 | any key "example-key"; # from anyone with the right key 27 | 127.0.0.1; # from localhost 28 | }; 29 | 30 | // When a change happens to this zone, the following IP 31 | // addresses and ports will be notified. 32 | also-notify { 33 | 127.0.0.1 port 5353 key "example-key"; 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /src/adapter-pcapfile.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007 by Errata Security, All Rights Reserved 2 | * Programer(s): Robert David Graham [rdg] 3 | */ 4 | #ifndef __PCAPFILE_H 5 | #define __PCAPFILE_H 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | #include 10 | 11 | struct PcapFile; 12 | 13 | 14 | unsigned pcapfile_datalink(struct PcapFile *handle); 15 | 16 | void pcapfile_writeframe( 17 | struct PcapFile *capfile, 18 | const void *buffer, 19 | unsigned buffer_size, 20 | unsigned original_length, 21 | unsigned time_sec, 22 | unsigned time_usec 23 | ); 24 | 25 | struct PcapFile *pcapfile_openread(const char *capfilename); 26 | struct PcapFile *pcapfile_openwrite(const char *capfilename, unsigned linktype); 27 | struct PcapFile *pcapfile_openappend(const char *capfilename, unsigned linktype); 28 | 29 | unsigned pcapfile_percentdone(struct PcapFile *handle, uint64_t *r_bytes_read); 30 | 31 | void pcapfile_get_timestamps(struct PcapFile *handle, time_t *start, time_t *end); 32 | 33 | /** 34 | * Set a "maximum" size for a file. When the current file fills up with data, 35 | * it will close that file and open a new one, then continue to write 36 | * from that point on in the new file. 37 | */ 38 | void pcapfile_set_max(struct PcapFile *capfile, unsigned max_megabytes, unsigned max_files); 39 | 40 | /** 41 | * Read a single frame from the file. 42 | * Returns 0 if failed to read (from error or end of file), and 43 | * returns 1 if successful. 44 | */ 45 | int pcapfile_readframe( 46 | struct PcapFile *capfile, 47 | unsigned *r_time_secs, 48 | unsigned *r_time_usecs, 49 | unsigned *r_original_length, 50 | unsigned *r_captured_length, 51 | unsigned char *buf, 52 | unsigned sizeof_buf 53 | ); 54 | 55 | 56 | void pcapfile_close(struct PcapFile *handle); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | #endif /*__PCAPFILE_H*/ 62 | -------------------------------------------------------------------------------- /src/adapter-pcaplive.h: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2007-2013 by Errata Security, All Rights Reserved 2 | ** Programer(s): Robert David Graham [rdg] 3 | **/ 4 | #ifndef __PCAPLIVE_H 5 | #define __PCAPLIVE_H 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifdef STATICPCAP 11 | /* Normal, we "dynamically" link to the libpcap library. However, on 12 | * some platforms, we might want to statically link to it instead. */ 13 | #include 14 | #else 15 | struct pcap_if { 16 | struct pcap_if *next; 17 | char *name; /* name to hand to "pcap_open_live()" */ 18 | char *description; /* textual description of interface, or NULL */ 19 | void *addresses; 20 | unsigned flags; /* PCAP_IF_ interface flags */ 21 | }; 22 | typedef struct pcap_if pcap_if_t; 23 | struct pcap_pkthdr { 24 | struct pcap_timeval { 25 | unsigned tv_sec; 26 | unsigned tv_usec; 27 | } ts; /* time stamp */ 28 | unsigned caplen; /* length of portion present */ 29 | unsigned len; /* length this packet (off wire) */ 30 | }; 31 | #endif 32 | 33 | 34 | struct pcap_send_queue; 35 | typedef struct pcap_send_queue pcap_sendqueue; 36 | 37 | struct bpf_insn; 38 | struct bpf_program { 39 | unsigned bf_len; 40 | struct bpf_insn *bf_insns; 41 | }; 42 | 43 | 44 | /* 45 | * Representation of an interface address. 46 | */ 47 | struct pcap_addr { 48 | struct pcap_addr *next; 49 | struct sockaddr *addr; /* address */ 50 | struct sockaddr *netmask; /* netmask for that address */ 51 | struct sockaddr *broadaddr; /* broadcast address for that address */ 52 | struct sockaddr *dstaddr; /* P2P destination address for that address */ 53 | }; 54 | 55 | 56 | typedef enum { 57 | PCAP_D_INOUT = 0, 58 | PCAP_D_IN, 59 | PCAP_D_OUT 60 | } pcap_direction_t; 61 | 62 | #ifndef PCAP_ERRBUF_SIZE 63 | #define PCAP_ERRBUF_SIZE 256 64 | #endif 65 | 66 | typedef void (*PCAP_HANDLE_PACKET)(unsigned char *v_seap, 67 | const struct pcap_pkthdr *framehdr, const unsigned char *buf); 68 | 69 | typedef void (*PCAP_CLOSE)(void *hPcap); 70 | typedef unsigned (*PCAP_DATALINK)(void *hPcap); 71 | typedef unsigned (*PCAP_DISPATCH)(void *hPcap, unsigned how_many_packets, PCAP_HANDLE_PACKET handler, void *handle_data); 72 | typedef int (*PCAP_FINDALLDEVS)(pcap_if_t **alldevs, char *errbuf); 73 | typedef const char *(*PCAP_LIB_VERSION)(void); 74 | typedef char *(*PCAP_LOOKUPDEV)(char *errbuf); 75 | typedef int (*PCAP_MAJOR_VERSION)(void *p); 76 | typedef int (*PCAP_MINOR_VERSION)(void *p); 77 | typedef void * (*PCAP_OPEN_LIVE)(const char *devicename, unsigned snap_length, unsigned is_promiscuous, unsigned read_timeout, char *errbuf); 78 | typedef void (*PCAP_FREEALLDEVS)(pcap_if_t *alldevs); 79 | typedef void * (*PCAP_GET_AIRPCAP_HANDLE)(void *p); 80 | typedef unsigned (*AIRPCAP_SET_DEVICE_CHANNEL)(void *p, unsigned channel); 81 | typedef unsigned (*CAN_TRANSMIT)(const char *devicename); 82 | typedef int (*PCAP_COMPILE)(void *, struct bpf_program *, const char *, int, unsigned); 83 | typedef void (*PCAP_PERROR)(void *, char *); 84 | typedef int (*PCAP_SETFILTER)(void *, struct bpf_program *); 85 | typedef const unsigned char *(*PCAP_NEXT)(void *p, struct pcap_pkthdr *h); 86 | typedef int (*PCAP_SENDPACKET)(void *, const unsigned char *, int); 87 | typedef struct pcap_send_queue* (*PCAP_SENDQUEUE_ALLOC)(unsigned memsize); 88 | typedef void (*PCAP_SENDQUEUE_DESTROY)(struct pcap_send_queue* queue); 89 | typedef int (*PCAP_SENDQUEUE_QUEUE)(struct pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const unsigned char *pkt_data); 90 | typedef unsigned (*PCAP_SENDQUEUE_TRANSMIT)(void *p, struct pcap_send_queue* queue, int sync); 91 | typedef int (*PCAP_SETDIRECTION)(void *, pcap_direction_t); 92 | 93 | struct PCAPLIVE 94 | { 95 | unsigned func_err:1; 96 | unsigned is_available:1; 97 | unsigned is_printing_debug:1; 98 | unsigned status; 99 | unsigned errcode; 100 | 101 | PCAP_CLOSE close; 102 | PCAP_DATALINK datalink; 103 | PCAP_DISPATCH dispatch; 104 | PCAP_FINDALLDEVS findalldevs; 105 | PCAP_FREEALLDEVS freealldevs; 106 | PCAP_LOOKUPDEV lookupdev; 107 | PCAP_LIB_VERSION lib_version; 108 | PCAP_MAJOR_VERSION major_version; 109 | PCAP_MINOR_VERSION minor_version; 110 | PCAP_OPEN_LIVE open_live; 111 | PCAP_GET_AIRPCAP_HANDLE get_airpcap_handle; 112 | AIRPCAP_SET_DEVICE_CHANNEL airpcap_set_device_channel; 113 | //AIRPCAP_SET_FCS_PRESENCE airpcap_set_fcs_presence; 114 | //BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); 115 | PCAP_COMPILE compile; 116 | PCAP_PERROR perror; 117 | PCAP_SETFILTER setfilter; 118 | PCAP_NEXT next; 119 | PCAP_SENDPACKET sendpacket; 120 | PCAP_SENDQUEUE_ALLOC sendqueue_alloc; 121 | PCAP_SENDQUEUE_DESTROY sendqueue_destroy; 122 | PCAP_SENDQUEUE_QUEUE sendqueue_queue; 123 | PCAP_SENDQUEUE_TRANSMIT sendqueue_transmit; 124 | PCAP_SETDIRECTION setdirection; 125 | 126 | CAN_TRANSMIT can_transmit; 127 | }; 128 | extern struct PCAPLIVE pcap; 129 | 130 | /** 131 | * Initialize the pcap subsystem by loading the DLL or shared objects. 132 | */ 133 | void pcaplive_init(); 134 | 135 | void pcaplive_shutdown(); 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | #endif /*__PCAPLIVE_H*/ 141 | -------------------------------------------------------------------------------- /src/adapter-recv.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "adapter.h" 3 | #include "thread.h" 4 | #include "proto-dns-compressor.h" 5 | #include "proto-dns-formatter.h" 6 | #include "resolver.h" 7 | #include "thread.h" 8 | #include "db-rrset.h" 9 | 10 | #include 11 | 12 | #define VERIFY_REMAINING(n) if (offset+(n) > max) return; 13 | 14 | /**************************************************************************** 15 | ****************************************************************************/ 16 | int 17 | adapter_has_ipv4(const struct Adapter *adapter, unsigned ipv4) 18 | { 19 | unsigned i; 20 | 21 | for (i=0; iipv4_count; i++) { 22 | if (adapter->ipv4[i].address == (ipv4 & adapter->ipv4[i].mask)) 23 | return 1; 24 | } 25 | return 0; 26 | } 27 | 28 | /**************************************************************************** 29 | ****************************************************************************/ 30 | void 31 | proto_ethernet_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max) 32 | { 33 | frame->net_protocol = NET_ETHERNET; 34 | 35 | VERIFY_REMAINING(14); 36 | frame->mac_src = &px[offset+6]; 37 | frame->mac_dst = &px[offset+0]; 38 | frame->ethertype = px[offset+12]<<8 | px[offset+13]; 39 | offset += 14; 40 | 41 | switch (frame->ethertype) { 42 | case 0x0800: 43 | proto_ip_parse(frame, px, offset, max); 44 | break; 45 | case 0x0806: 46 | proto_arp_parse(frame, px, offset, max); 47 | break; 48 | /*TODO: add 802.1a */ 49 | } 50 | } 51 | 52 | /**************************************************************************** 53 | ****************************************************************************/ 54 | void 55 | network_receive(struct Frame *frame, 56 | struct Thread *thread, 57 | struct Adapter *adapter, 58 | unsigned secs, 59 | unsigned usecs, 60 | const unsigned char *px, 61 | unsigned length) 62 | { 63 | 64 | frame->adapter = adapter; 65 | frame->thread = thread; 66 | frame->time_secs = secs; 67 | frame->time_usecs = usecs; 68 | frame->net_protocol = 0; 69 | 70 | /* 71 | * PARSE FIRST THEN PROCESS REQ:[d7Unn4] 72 | * 73 | * This parses Ethernet, IP, UDP, and DNS. 74 | * 75 | * TODO: this will change a bit once I add TCP handling 76 | */ 77 | proto_ethernet_parse(frame, px, 0, length); 78 | 79 | /* 80 | * Reject packets that aren't sent to us. 81 | */ 82 | if (!adapter_has_ipv4(adapter, frame->ip_dst)) 83 | return; 84 | 85 | /* 86 | * AT this point, we have a fully validated packet. Now we will 87 | * go through and generate a response 88 | */ 89 | switch (frame->net_protocol) { 90 | case NET_ARP: 91 | proto_arp_process(frame, frame->arp); 92 | return; 93 | case NET_ICMP: 94 | proto_icmp_process(frame, frame->icmp); 95 | return; 96 | default: 97 | return; 98 | case NET_DNS: 99 | if (!frame->dns->is_valid) 100 | return; 101 | break; 102 | } 103 | 104 | /* 105 | * Now that PARSING is done, process the DNS request 106 | */ 107 | { 108 | struct Packet pkt; 109 | struct DNS_OutgoingResponse response[1]; 110 | struct DNS_Incoming *request = frame->dns; 111 | 112 | 113 | /* Start a "response" structure based on the "request" */ 114 | resolver_init(response, 115 | request->query_name.name, 116 | request->query_name.length, 117 | request->query_type, 118 | request->id, 119 | request->opcode); 120 | 121 | /* 122 | * !!! IMPORTANT !!! 123 | * 124 | * Take the request, run the DNS resolver algorithm, and produce 125 | * a response structure. 126 | * 127 | */ 128 | resolver_algorithm(thread->catalog_run, response, request); 129 | 130 | 131 | /* 132 | * format the respone packet 133 | */ 134 | pkt = frame_create_response(frame, NET_UDP); 135 | dns_format_response(response, &pkt); 136 | 137 | /* 138 | * Transmit the response 139 | */ 140 | frame_xmit_response(frame, &pkt); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/adapter.c: -------------------------------------------------------------------------------- 1 | #include "adapter.h" 2 | #include "unusedparm.h" 3 | #include "util-realloc2.h" 4 | #include 5 | #include 6 | 7 | enum { 8 | DRIVER_LIBPCAP=1, 9 | DRIVER_LINUXRING=2, 10 | DRIVER_BPF=4, 11 | DRIVER_PFRING=8, 12 | DRIVER_DPDKPOLL=16, 13 | DRIVER_BSDNETMAP=32, 14 | }; 15 | struct AdapterListItem 16 | { 17 | char *adapter_name; 18 | char mac_address[6*3]; 19 | char *driver; 20 | }; 21 | 22 | const struct AdapterListItem * 23 | adapter_list(unsigned *r_count) 24 | { 25 | static struct AdapterListItem list[64]; 26 | static unsigned count; 27 | unsigned i; 28 | 29 | UNUSEDPARM(r_count); 30 | 31 | /* Free the old list */ 32 | for (i=0; iipv4_count < sizeof(adapter->ipv4)/sizeof(adapter->ipv4[0])) { 44 | unsigned i = adapter->ipv4_count++; 45 | adapter->ipv4[i].address = ipv4_address; 46 | adapter->ipv4[i].mask = mask; 47 | } 48 | } 49 | 50 | struct Adapter * 51 | adapter_create(ALLOC_PACKET alloc_packet, XMIT_PACKET xmit_packet, void *userdata) 52 | { 53 | struct Adapter *adapter; 54 | 55 | adapter = REALLOC2(0, 1, sizeof(adapter[0])); 56 | memset(&adapter[0], 0, sizeof(adapter[0])); 57 | 58 | adapter->alloc_packet = alloc_packet; 59 | adapter->xmit_packet = xmit_packet; 60 | adapter->userdata = userdata; 61 | 62 | return adapter; 63 | } 64 | 65 | void 66 | adapter_destroy(struct Adapter *adapter) 67 | { 68 | free(adapter); 69 | } 70 | -------------------------------------------------------------------------------- /src/adapter.h: -------------------------------------------------------------------------------- 1 | #ifndef ADAPTER_H 2 | #define ADAPTER_H 3 | #include "packet.h" 4 | #include 5 | struct Thread; 6 | struct Adapter; 7 | 8 | typedef struct Packet (*ALLOC_PACKET)(struct Adapter *, struct Thread *); 9 | typedef void (*XMIT_PACKET)(struct Adapter *, struct Thread *, struct Packet *); 10 | 11 | 12 | struct Adapter 13 | { 14 | ALLOC_PACKET alloc_packet; 15 | XMIT_PACKET xmit_packet; 16 | void *userdata; 17 | 18 | struct { 19 | unsigned char address[6]; 20 | } mac[1]; 21 | 22 | unsigned ipv4_count; 23 | struct { 24 | unsigned address; 25 | unsigned mask; 26 | } ipv4[8]; 27 | 28 | 29 | /** 30 | * The maximum length we can transmit. This will be set before the 31 | * adapter is open. It can also be: 32 | * - 1514 for normal Ethernet 33 | * - 1518 for 802.11q Ethernet 34 | * - 1600 for baby giant Ethernet 35 | * - 7935 for WiFi 36 | * - 9000 for jumbo frames 37 | * - 65536 for super jumbo frames (the max possible) 38 | */ 39 | unsigned frame_size; 40 | 41 | unsigned ipv6_count; 42 | struct { 43 | unsigned char address[16]; 44 | unsigned char mask[16]; 45 | } ipv6[8]; 46 | 47 | struct pcap_t *pcap; 48 | struct pcap_send_queue *sendq; 49 | struct pfring *ring; 50 | 51 | }; 52 | 53 | int adapter_has_ipv4(const struct Adapter *adapter, unsigned ipv4); 54 | 55 | struct Adapter *adapter_create(ALLOC_PACKET alloc_packet, XMIT_PACKET xmit_packet, void *userdata); 56 | void adapter_destroy(struct Adapter *adapter); 57 | struct Packet adapter_create_request_udp(struct Adapter *adapter, unsigned ip_dst, unsigned port_dst); 58 | void adapter_xmit(struct Adapter *adapter, struct Thread *thread, struct Packet *packet); 59 | void adapter_add_ipv4(struct Adapter *adapter, unsigned ipv4_address, unsigned mask); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/conf-addrlist.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_ADDRMATCHLIST_H 2 | #define CONF_ADDRMATCHLIST_H 3 | 4 | 5 | struct Cfg_AddrMatchList * 6 | conf_load_addrlist(const struct Configuration *cfg, 7 | const struct ConfParse *parse, 8 | const struct CF_Child *parent, 9 | const struct CF_Token *name, 10 | unsigned port); 11 | 12 | void 13 | conf_addrmatch_free(struct Cfg_AddrMatchList *cfg); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/conf-error.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_ERROR_H 2 | #define CONF_ERROR_H 3 | struct ConfParse; 4 | struct CF_Token; 5 | 6 | //void WARNING(struct CF_Token token, const char *fmt, ...); 7 | 8 | void CONF_ERR(const struct ConfParse *parse, const struct CF_Token *token, const char *fmt, ...); 9 | 10 | /* when the 'name' of a statement is unknown */ 11 | void CONF_OPTION_UNKNOWN(const struct ConfParse *parse, const struct CF_Token *token); 12 | 13 | /* when the value has been duplicated*/ 14 | void CONF_OPTION_DUPLICATE(const struct ConfParse *parse, const struct CF_Token *token); 15 | 16 | /* when the 'value' of a statement is unknown or bad*/ 17 | void CONF_VALUE_BAD(const struct ConfParse *parse, const struct CF_Token *token); 18 | 19 | /* when the 'value' of a statement is missing */ 20 | void CONF_VALUE_MISSING(const struct ConfParse *parse, const struct CF_Token *token); 21 | 22 | void CONF_FEATURE_UNSUPPORTED(const struct ConfParse *parse, const struct CF_Token *token); 23 | 24 | /* like 'feature-supported', but specifically this feature since it 25 | * appears in so many places */ 26 | void CONF_RECURSION_UNSUPPORTED(const struct ConfParse *parse, const struct CF_Token *token); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/conf-keys.c: -------------------------------------------------------------------------------- 1 | #include "conf-parse.h" 2 | #include "conf-load.h" 3 | #include "conf-keys.h" 4 | #include "configuration.h" 5 | #include "crypto-base64.h" 6 | #include "util-realloc2.h" 7 | #include 8 | #include 9 | 10 | /**************************************************************************** 11 | ****************************************************************************/ 12 | const struct Cfg_Key * 13 | cfg_key_lookup(const struct Configuration *cfg, const char *name) 14 | { 15 | size_t i; 16 | for (i=0; ikeys_length; i++) { 17 | if (strcmp(name, cfg->keys[i]->name) == 0) 18 | return cfg->keys[i]; 19 | } 20 | return 0; 21 | } 22 | 23 | /**************************************************************************** 24 | ****************************************************************************/ 25 | void 26 | conf_load_key(struct Configuration *cfg, const struct ConfParse *parse, const struct CF_Child *parent) 27 | { 28 | struct CF_Token value = confparse_node_gettoken(parse, parent, 1); 29 | struct Cfg_Key *key; 30 | size_t i; 31 | 32 | /* key's must have a name */ 33 | if (value.name_length == 0) { 34 | CONF_VALUE_MISSING(parse, &value); 35 | return; 36 | } 37 | 38 | key = MALLOC2(sizeof(*key)); 39 | memset(key, 0, sizeof(*key)); 40 | 41 | key->name = MALLOC2(value.name_length + 1); 42 | memcpy(key->name, value.name, value.name_length + 1); 43 | 44 | 45 | 46 | for (i=0; ichild_count; i++) { 47 | struct CF_Child child = confparse_node_getchild(parse, parent, i); 48 | struct CF_Token token = confparse_node_gettoken(parse, &child, 0); 49 | 50 | value = confparse_node_gettoken(parse, &child, 1); 51 | 52 | switch (lookup_token(&token)) { 53 | case S_ALGORITHM: 54 | switch (lookup_token(&value)) { 55 | case S_HMAC_MD5: 56 | case S_HMAC_SHA256: 57 | case S_HMAC_SHA512: 58 | break; 59 | default: 60 | CONF_VALUE_BAD(parse, &value); 61 | break; 62 | } 63 | break; 64 | case S_SECRET: 65 | if (token.name_length == 0) { 66 | CONF_VALUE_MISSING(parse, &value); 67 | } else { 68 | unsigned char *secret; 69 | size_t secret_length = value.name_length; 70 | 71 | secret = MALLOC2(secret_length); 72 | 73 | secret_length = base64_decode( secret, 74 | secret_length, 75 | value.name, 76 | value.name_length); 77 | if (secret_length == 0) { 78 | CONF_VALUE_BAD(parse, &value); 79 | free(secret); 80 | } else { 81 | if (key->secret) { 82 | CONF_OPTION_DUPLICATE(parse, &value); 83 | free(key->secret); 84 | } 85 | key->secret = secret; 86 | key->secret_length = secret_length; 87 | } 88 | } 89 | 90 | break; 91 | default: 92 | CONF_OPTION_UNKNOWN(parse, &value); 93 | break; 94 | } 95 | } 96 | 97 | if (key->algorithm == 0) 98 | key->algorithm = S_HMAC_MD5; 99 | if (key->name == 0 || key->secret == 0) { 100 | if (key->name) 101 | free(key->name); 102 | if (key->secret) 103 | free(key->secret); 104 | free(key); 105 | return; 106 | } 107 | 108 | /* 109 | * Now add to our list of keys 110 | */ 111 | cfg->keys = REALLOC2(cfg->keys, sizeof(cfg->keys[0]), cfg->keys_length + 1); 112 | 113 | cfg->keys[cfg->keys_length++] = key; 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/conf-keys.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_KEYS_H 2 | #define CONF_KEYS_H 3 | 4 | void conf_load_key(struct Configuration *cfg, const struct ConfParse *parse, const struct CF_Child *parent); 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/conf-load.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_LOAD_H 2 | #define CONF_LOAD_H 3 | #include 4 | 5 | struct CF_Token; 6 | struct ConfParse; 7 | struct CF_Child; 8 | struct Configuration; 9 | 10 | void confload_configuration(struct Configuration *cfg, const char *filename, const struct CF_Token *token); 11 | 12 | int confload_toplevel(struct ConfParse *parse, void *data, const struct CF_Child *node); 13 | 14 | 15 | void conf_load_options(struct Configuration *cfg, const struct ConfParse *parse, const struct CF_Child *parent); 16 | 17 | 18 | 19 | /** 20 | * Translate a string to an integer, such as looking up the token 21 | * with the value of "options", returning an integer S_OPTIONS. 22 | * @token 23 | * A string parsed from the configuration file. 24 | * @returns 25 | * A integer enumeration ConfTokenId. 26 | */ 27 | size_t lookup_token(const struct CF_Token *token); 28 | 29 | enum ConfTokenId { 30 | S_UNKNOWN, 31 | S_ACL, 32 | S_ALGORITHM, 33 | S_ALLOW_NEW_ZONES, 34 | S_ALLOW_NOTIFY, 35 | S_ALLOW_TRANSFER, 36 | S_ALSO_NOTIFY, 37 | S_ALT_TRANSFER_SOURCE, 38 | S_ALT_TRANSFER_SOURCE_V6, 39 | S_AUTH_NXDOMAIN, 40 | S_DIRECTORY, 41 | S_DNSSEC_VALIDATION, 42 | S_FILE, 43 | S_FORWARDERS, 44 | S_GSS_TSIG, 45 | S_HMAC_MD5, 46 | S_HMAC_SHA1, 47 | S_HMAC_SHA224, 48 | S_HMAC_SHA256, 49 | S_HMAC_SHA384, 50 | S_HMAC_SHA512, 51 | S_HOSTNAME, 52 | S_INCLUDE, 53 | S_INTERFACE_INTERVAL, 54 | S_KEY, 55 | S_LISTEN_ON, 56 | S_LISTEN_ON_V6, 57 | S_MASTER, 58 | S_NO, 59 | S_NONE, 60 | S_OPTIONS, 61 | S_PID_FILE, 62 | S_PORT, 63 | S_RECURSION, 64 | S_SECRET, 65 | S_SERVER_ID, 66 | S_SLAVE, 67 | S_TRANSFER_SOURCE, 68 | S_TRANSFER_SOURCE_V6, 69 | S_TYPE, 70 | S_VERSION, 71 | S_YES, 72 | S_ZONE, 73 | S_ZONE_DIRECTORY, 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/conf-options.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_OPTIONS_H 2 | #define CONF_OPTIONS_H 3 | 4 | 5 | struct Cfg_AddrMatchList * 6 | conf_load_addrlist(const struct Configuration *cfg, 7 | const struct ConfParse *parse, 8 | const struct CF_Child *parent, 9 | const struct CF_Token *name, 10 | unsigned port); 11 | 12 | void 13 | conf_addrmatch_free(struct Cfg_AddrMatchList *cfg); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/conf-parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | BIND9 named.conf parser 3 | 4 | This is a syntax-free parser for BIND9 configuration files. 5 | It doesn't understand any of the things it's parsing, 6 | but instead just parses tokens, strings, and the hierarchical 7 | structure. It's up to the host program to process the 8 | strings in order to analyze the "statements" within the file. 9 | 10 | A named.conf file looks like the following: 11 | 12 | options { 13 | forwarders { 14 | 192.168.1.1; 15 | 10.2.3.4; 16 | }; 17 | statistics-file "/var/named/data/named_stats.txt"; 18 | dump-file "/var/named/data/cache_dump.db"; 19 | directory "/var/named"; 20 | }; 21 | zone "domain.com" { 22 | type slave; 23 | masters { 24 | 192.168.1.1; 25 | }; 26 | }; 27 | 28 | The name at the root (in this case, "option" and "zone") is known 29 | as a "statement". When parsing the file, a callback function 30 | will be called for each complete statement (and all leaf nodes). 31 | 32 | This is for efficiency. One statement is "include", which the parser 33 | doesn't handle natively, but which the user code will have to handle 34 | explicitly, recursively calling the parser. Another important statement 35 | is "zone". A server might support a million zones. This can be very 36 | inefficient to load the entire configuration file, with all statements. 37 | It's much more efficient to process each statement one-at-a-time. 38 | 39 | 40 | */ 41 | #ifndef CONF_PARSE_H 42 | #define CONF_PARSE_H 43 | #include 44 | #include 45 | #include "conf-error.h" 46 | struct ConfParse; 47 | struct CF_Internals; 48 | 49 | struct CF_Child 50 | { 51 | char *name; 52 | size_t name_length; 53 | 54 | size_t token_count; 55 | size_t child_count; 56 | 57 | struct CF_Internals *internals; 58 | }; 59 | 60 | struct CF_Token 61 | { 62 | char *name; 63 | unsigned name_length; 64 | const char *filename; 65 | unsigned is_string:1; 66 | unsigned linenumber:31; 67 | }; 68 | 69 | typedef int (*CONF_STATEMENT_CALLBACK)(struct ConfParse *conf, void *data, const struct CF_Child *node); 70 | 71 | 72 | const char *confparse_err_file_line(const struct CF_Child *node, size_t *line_number); 73 | 74 | 75 | /** 76 | * Enumerates the list of tokens at a node 77 | */ 78 | struct CF_Token confparse_node_gettoken(const struct ConfParse *conf, const struct CF_Child *node, size_t index); 79 | 80 | /** 81 | * Enumerates child nodes in order to walk the configuration tree. 82 | */ 83 | struct CF_Child confparse_node_getchild(const struct ConfParse *conf, const struct CF_Child *node, size_t index); 84 | 85 | /** 86 | * Create a BIND9 conf file parser 87 | */ 88 | struct ConfParse *confparse_create(const char *filename, CONF_STATEMENT_CALLBACK fn, void *data); 89 | 90 | /** 91 | * Free/destory the memory from a parser 92 | */ 93 | void confparse_destroy(struct ConfParse *conf); 94 | 95 | /** 96 | * Print the entire structure, for debugging purposes, or saving into a file 97 | */ 98 | void confparse_print_statement(struct ConfParse *conf, FILE *fp); 99 | 100 | /** 101 | * Parse all the statements into one big structure 102 | */ 103 | void confparse_parse(struct ConfParse *conf, const unsigned char *data, size_t sizeof_data); 104 | 105 | 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/conf-selftest.c: -------------------------------------------------------------------------------- 1 | const char test1[] = 2 | "# this is a test\n" 3 | "// this is also a test\n" 4 | "/* this is \n too a test */\n" 5 | "\n" 6 | "//defining acl's\n" 7 | "// simple ip address acl\n" 8 | "key marty { \n" 9 | " algorithm hmac-md5; \n" 10 | " secret \"dG9vIG1hbnkgc2VjcmV0cw==\";\n" 11 | "};\n" 12 | "\n" 13 | "acl \"someips\" {\n" 14 | " 10.0.0.1; 192.168.23.1; 192.168.23.15;\n" 15 | "};\n" 16 | " // ip address acl with '/' format\n" 17 | " acl \"moreips\" {\n" 18 | " 10.0.0.1; \n" 19 | " 192.168.23.128/25; // 128 IPs\n" 20 | "};\n" 21 | "// nested acl\n" 22 | "acl \"allips\" {\n" 23 | " \"someips\"; \n" 24 | " \"moreips\";\n" 25 | "};\n" 26 | "// messy acl\n" 27 | "acl \"complex\" {\n" 28 | " \"someips\"; \n" 29 | " 10.0.15.0/24;\n" 30 | " !10.0.16.1/24; // negated\n" 31 | " {10.0.17.1;10.0.18.2;}; // nested\n" 32 | " };\n" 33 | "options {\n" 34 | " pid-file \"./named.pid\"; # comment \n" 35 | " directory \"/var/named\"; \n" 36 | " pid-file \"./named.pid\";\n" 37 | " port /* testing */ 72 ; \n" 38 | " interface-interval 1234 ; // comment \n" 39 | " version \"this is a version\";" 40 | " version none;\n" 41 | " hostname \"test 1\";\n" 42 | " server-id \"test 2\";\n" 43 | "};\n" 44 | "\n" 45 | "// using acl's\n" 46 | "zone \"example.com\" {\n" 47 | " type slave;\n" 48 | " file \"slave.example.com\";\n" 49 | " allow-notify {\"complex\";}; \n" 50 | "};\n" 51 | "zone \"example.net\" {\n" 52 | " type slave;\n" 53 | " masters {192.168.2.3;192.168.2.4};\n" 54 | " file \"slave.example.net\";\n" 55 | " allow-transfer {\"none\";}; // this is a special acl\n" 56 | "};\n" 57 | ; 58 | 59 | /* 60 | CONF FILE PARSER SELF-TEST 61 | 62 | This is a small unit test to verify that the conf 63 | file parser is working correctly 64 | */ 65 | #include "configuration.h" 66 | #include "conf-load.h" 67 | #include "conf-parse.h" 68 | #include 69 | 70 | 71 | /**************************************************************************** 72 | ****************************************************************************/ 73 | int 74 | conf_selftest(void) 75 | { 76 | struct ConfParse *parse; 77 | struct Configuration *cfg = cfg_create(); 78 | 79 | parse = confparse_create("", confload_toplevel, cfg); 80 | confparse_parse(parse, (const unsigned char *)test1, sizeof(test1) - 1); 81 | confparse_destroy(parse); 82 | 83 | if (cfg->options.directory == 0 || strcmp(cfg->options.directory, "/var/named") != 0) 84 | return -1; 85 | 86 | if (cfg->options.pid_file == 0 || strcmp(cfg->options.pid_file, "/var/named/named.pid") != 0) 87 | return -1; 88 | 89 | if (cfg->options.hostname == 0 || strcmp(cfg->options.hostname, "test 1") != 0) 90 | return -1; 91 | if (cfg->options.server_id == 0 || strcmp(cfg->options.server_id, "test 2") != 0) 92 | return -1; 93 | 94 | if (cfg->data_plane.port != 72) 95 | return -1; 96 | 97 | if (cfg->options.version != NULL || cfg->options.version_length != 0) 98 | return -1; 99 | 100 | /* 101 | * key "name" { 102 | * }; 103 | */ 104 | { 105 | const struct Cfg_Key *key; 106 | 107 | key = cfg_key_lookup(cfg, "not-a-key"); 108 | if (key != NULL) 109 | return -1; 110 | 111 | key = cfg_key_lookup(cfg, "marty"); 112 | if (key == NULL) 113 | return -1; 114 | if (key->secret_length != strlen("too many secrets")) 115 | return -1; 116 | if (memcmp(key->secret, "too many secrets", strlen("too many secrets")) != 0) 117 | return -1; 118 | 119 | } 120 | 121 | return 0; /* success */ 122 | } 123 | 124 | -------------------------------------------------------------------------------- /src/conf-trackfile.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_TRACKFILE_H 2 | #define CONF_TRACKFILE_H 3 | 4 | struct Conf_TrackFile *conf_trackfile_create(void); 5 | void conf_trackfile_destroy(struct Conf_TrackFile *tf); 6 | 7 | /** 8 | * Keep track of the configuration file (name, time, size), and every 9 | * sub-configuration file that's been added through the "include" 10 | * statement 11 | */ 12 | void conf_trackfile_add(struct Conf_TrackFile *tf, const char *filename); 13 | 14 | /** 15 | * @return the number of files we are current tracking. This is for 16 | * enumerating the files. 17 | */ 18 | unsigned conf_trackfile_count(const struct Conf_TrackFile *tf); 19 | 20 | /** 21 | * @return the indexed filename, where 'index' must be less than the total 22 | * count of files we are tracking. This is a simple accessor function for 23 | * enumerating the files in our list. 24 | */ 25 | const char *conf_trackfile_filename(const struct Conf_TrackFile *tf, unsigned index); 26 | 27 | /** 28 | * During the processing of a SIGHUP, test the new list of configuration 29 | * files in order to see if they have changed. If not, then we can 30 | * skip reconfiguration 31 | */ 32 | unsigned 33 | conf_trackfile_has_changed(const struct Conf_TrackFile *tf); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/conf-zone.c: -------------------------------------------------------------------------------- 1 | #include "conf-zone.h" 2 | #include "configuration.h" 3 | #include "conf-load.h" 4 | #include "conf-parse.h" 5 | #include "util-filename.h" 6 | #include "conf-addrlist.h" 7 | #include "util-realloc2.h" 8 | #include "string_s.h" 9 | #include 10 | #include 11 | 12 | /**************************************************************************** 13 | ****************************************************************************/ 14 | const struct Cfg_Zone * 15 | conf_zone_lookup(const struct Configuration *cfg, const char *name) 16 | { 17 | unsigned i; 18 | 19 | for (i=0; izones_length; i++) { 20 | const struct Cfg_Zone *zone = cfg->zones[i]; 21 | 22 | if (strcasecmp(zone->name, name) == 0) 23 | return zone; 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | 30 | /**************************************************************************** 31 | ****************************************************************************/ 32 | struct Cfg_Zone * 33 | conf_zone_create(const char *name, size_t name_length) 34 | { 35 | struct Cfg_Zone *zone; 36 | 37 | zone = MALLOC2(sizeof(*zone)); 38 | 39 | memset(zone, 0, sizeof(*zone)); 40 | if (zone == NULL) { 41 | exit(1); 42 | } 43 | 44 | if (name_length) { 45 | zone->name = MALLOC2(name_length + 1); 46 | if (zone->name == NULL) 47 | exit(1); 48 | memcpy(zone->name, name, name_length + 1); 49 | } 50 | 51 | while (name_length && zone->name[name_length-1] == '.') 52 | zone->name[--name_length] = '\0'; 53 | 54 | while (name_length && zone->name[0] == '.') { 55 | memmove(zone->name, zone->name+1, name_length); 56 | name_length--; 57 | } 58 | 59 | return zone; 60 | } 61 | 62 | /**************************************************************************** 63 | ****************************************************************************/ 64 | void 65 | conf_load_zone_item( struct Configuration *cfg, 66 | const struct ConfParse *parse, 67 | const struct CF_Child *parent, 68 | struct Cfg_Zone *zone 69 | ) 70 | { 71 | struct CF_Token token = confparse_node_gettoken(parse, parent, 0); 72 | struct CF_Token value = confparse_node_gettoken(parse, parent, 1); 73 | 74 | switch (lookup_token(&token)) { 75 | case S_TYPE: 76 | if (zone->type != 0) 77 | CONF_OPTION_DUPLICATE(parse, &token); 78 | switch (lookup_token(&value)) { 79 | case S_MASTER: 80 | zone->type = CFGZ_MASTER; 81 | break; 82 | case S_SLAVE: 83 | zone->type = CFGZ_SLAVE; 84 | break; 85 | default: 86 | CONF_VALUE_BAD(parse, &value); 87 | } 88 | break; 89 | case S_FILE: 90 | if (zone->file != 0) { 91 | CONF_OPTION_DUPLICATE(parse, &token); 92 | free(zone->file); 93 | zone->file = NULL; 94 | } 95 | if (value.name_length == 0) { 96 | CONF_VALUE_BAD(parse, &value); 97 | } else { 98 | zone->file = filename_combine(cfg->options.directory, value.name); 99 | 100 | } 101 | break; 102 | case S_ALLOW_NOTIFY: 103 | if (zone->allow_notify) { 104 | CONF_OPTION_DUPLICATE(parse, &token); 105 | conf_addrmatch_free(zone->allow_notify); 106 | zone->allow_notify = NULL; 107 | } 108 | zone->allow_notify = conf_load_addrlist(cfg, parse, parent, 0, 65536); 109 | break; 110 | case S_ALLOW_TRANSFER: 111 | if (zone->allow_transfer) { 112 | CONF_OPTION_DUPLICATE(parse, &token); 113 | conf_addrmatch_free(zone->allow_transfer); 114 | zone->allow_transfer = NULL; 115 | } 116 | zone->allow_transfer = conf_load_addrlist(cfg, parse, parent, 0, 65536); 117 | break; 118 | case S_ALSO_NOTIFY: 119 | if (zone->also_notify) { 120 | CONF_OPTION_DUPLICATE(parse, &token); 121 | conf_addrmatch_free(zone->also_notify); 122 | zone->also_notify = NULL; 123 | } 124 | zone->also_notify = conf_load_addrlist(cfg, parse, parent, 0, 65536); 125 | break; 126 | default: 127 | CONF_OPTION_UNKNOWN(parse, &token); 128 | break; 129 | } 130 | } 131 | 132 | void 133 | conf_zone_append( struct Configuration *cfg, struct Cfg_Zone *zone) 134 | { 135 | cfg->zones = REALLOC2(cfg->zones, sizeof(cfg->zones[0]), cfg->zones_length + 1); 136 | cfg->zones[cfg->zones_length++] = zone; 137 | } 138 | 139 | /**************************************************************************** 140 | ****************************************************************************/ 141 | void 142 | conf_load_zone( struct Configuration *cfg, 143 | const struct ConfParse *parse, 144 | const struct CF_Child *parent) 145 | { 146 | struct CF_Token value = confparse_node_gettoken(parse, parent, 1); 147 | struct Cfg_Zone *zone; 148 | size_t i; 149 | 150 | if (value.name_length == 0) { 151 | CONF_VALUE_MISSING(parse, &value); 152 | return; 153 | } 154 | 155 | zone = conf_zone_create(value.name, value.name_length); 156 | 157 | /* 158 | * Parse all the options 159 | */ 160 | for (i=0; ichild_count; i++) { 161 | struct CF_Child child = confparse_node_getchild(parse, parent, i); 162 | 163 | conf_load_zone_item(cfg, parse, &child, zone); 164 | } 165 | 166 | /* 167 | * Add to our list of zones 168 | */ 169 | conf_zone_append(cfg, zone); 170 | } 171 | 172 | 173 | /**************************************************************************** 174 | ****************************************************************************/ 175 | void 176 | cfg_add_zonefile(struct Configuration *cfg, const char *filename) 177 | { 178 | struct Cfg_Zone *zone; 179 | 180 | /* Create an empty zone record -- we won't know the name of the zone 181 | * until we parse the file */ 182 | zone = conf_zone_create(0, 0); 183 | 184 | /* Add in the zonefile name */ 185 | zone->file = filename_combine(cfg->options.directory, filename); 186 | 187 | /* 188 | * Add to our list of zones 189 | */ 190 | cfg->zones = REALLOC2(cfg->zones, sizeof(cfg->zones[0]), cfg->zones_length + 1); 191 | cfg->zones[cfg->zones_length++] = zone; 192 | } 193 | -------------------------------------------------------------------------------- /src/conf-zone.h: -------------------------------------------------------------------------------- 1 | #ifndef CONF_ZONE_H 2 | #define CONF_ZONE_H 3 | #include 4 | struct Configuration; 5 | struct ConfParse; 6 | struct CF_Child; 7 | 8 | void 9 | conf_load_zone( struct Configuration *cfg, 10 | const struct ConfParse *parse, 11 | const struct CF_Child *parent); 12 | 13 | 14 | const struct Cfg_Zone *conf_zone_lookup(const struct Configuration *cfg, const char *name); 15 | void conf_zone_append( struct Configuration *cfg, struct Cfg_Zone *zone); 16 | struct Cfg_Zone *conf_zone_create(const char *name, size_t name_length); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/conf-zonedir.c: -------------------------------------------------------------------------------- 1 | #include "configuration.h" 2 | #include "logger.h" 3 | #include "pixie.h" 4 | #include "util-filename.h" 5 | #include "string_s.h" 6 | #include "util-realloc2.h" 7 | #include 8 | #include 9 | 10 | #if defined(_MSC_VER) 11 | #include 12 | #define stat64 _stat64 13 | #elif defined(__GNUC__) 14 | #define stat64 stat 15 | #include 16 | #endif 17 | 18 | /**************************************************************************** 19 | * Look for suffixes to strings, especially looking for file types like 20 | * ".conf" or ".zone" or ".pcap". 21 | * @return 1 if the string has that suffix, or 0 otherwise. 22 | ****************************************************************************/ 23 | static int 24 | ends_with(const char *string, const char *suffix) 25 | { 26 | size_t string_length = strlen(string); 27 | size_t suffix_length = strlen(suffix); 28 | 29 | if (suffix_length > string_length) 30 | return 0; 31 | 32 | return memcmp(string+string_length-suffix_length, suffix, suffix_length) == 0; 33 | } 34 | 35 | 36 | /**************************************************************************** 37 | * Recursively descened a file directory tree and create a list of 38 | * all filenames ending in ".zone". 39 | ****************************************************************************/ 40 | void 41 | directory_to_zonefile_list(struct Cfg_ZoneDir *zonedir, const char *in_dirname) 42 | { 43 | void *x; 44 | size_t dirname_length = strlen(in_dirname); 45 | char *dirname; 46 | 47 | dirname = MALLOC2(dirname_length + 1); 48 | memcpy(dirname, in_dirname, dirname_length + 1); 49 | 50 | /* strip trailing slashes, if there are any */ 51 | while (dirname_length && (dirname[dirname_length-1] == '/' || dirname[dirname_length-1] == '\\')) { 52 | dirname_length--; 53 | } 54 | 55 | /* 56 | * Start directory enumeration 57 | */ 58 | x = pixie_opendir(dirname); 59 | if (x == NULL) { 60 | LOG_ERR(C_DATABASE, "opendir(%s) failed: %s\n", dirname, strerror_x(errno)); 61 | free(dirname); 62 | return; /* no content */ 63 | } 64 | 65 | /* 66 | * 'for all zonefiles in this directory...' 67 | */ 68 | for (;;) { 69 | const char *filename; 70 | char *fullname; 71 | struct stat64 s; 72 | 73 | /* Get next filename */ 74 | filename = pixie_readdir(x); 75 | if (filename == NULL) 76 | break; 77 | 78 | /* Skip the bad names */ 79 | if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) 80 | continue; 81 | 82 | /* get the full name */ 83 | fullname = filename_combine(dirname, filename); 84 | 85 | /* Get the file size/timestmap */ 86 | if (stat64(fullname, &s) != 0) { 87 | LOG_ERR(C_DATABASE, "stat(%s) failed: %s\n", dirname, strerror_x(errno)); 88 | free(fullname); 89 | continue; 90 | } 91 | 92 | /* if this is a directory, then recursively descend */ 93 | if (s.st_mode & S_IFDIR) { 94 | directory_to_zonefile_list(zonedir, fullname); 95 | free(fullname); 96 | continue; 97 | } 98 | 99 | /* add the name to our list 100 | * TODO: this should insert in sort order */ 101 | if (zonedir->file_count + 1 > zonedir->file_max) { 102 | zonedir->file_max = zonedir->file_max*2 + 1; 103 | zonedir->files = REALLOC2(zonedir->files, sizeof(zonedir->files[0]), zonedir->file_max); 104 | } 105 | 106 | if (!ends_with(filename, ".zone")) { 107 | free(fullname); 108 | continue; 109 | } 110 | 111 | zonedir->files[zonedir->file_count].filename = fullname; 112 | zonedir->files[zonedir->file_count].size = s.st_size; 113 | zonedir->files[zonedir->file_count].timestamp = s.st_mtime; 114 | zonedir->file_count++; 115 | } 116 | pixie_closedir(x); 117 | 118 | free(dirname); 119 | } 120 | -------------------------------------------------------------------------------- /src/configuration-adapter.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGURATION_ADAPTER_H 2 | #define CONFIGURATION_ADAPTER_H 3 | 4 | enum CoreSocketType { 5 | ST_Unknown, ST_IPv4, ST_IPv6, ST_Any, ST_Raw, 6 | }; 7 | 8 | struct CoreSocketItem 9 | { 10 | int fd; 11 | enum CoreSocketType type; 12 | unsigned proto; 13 | unsigned port; 14 | char *ifname; 15 | union { 16 | unsigned v4; 17 | unsigned char v6[16]; 18 | } ip; 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /src/configuration.c: -------------------------------------------------------------------------------- 1 | #include "configuration.h" 2 | #include "conf-trackfile.h" 3 | #include "util-realloc2.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | /**************************************************************************** 10 | ****************************************************************************/ 11 | struct Configuration *cfg_create(void) 12 | { 13 | struct Configuration *cfg; 14 | 15 | cfg = REALLOC2(0, 1, sizeof(*cfg)); 16 | memset(cfg, 0, sizeof(cfg[0])); 17 | 18 | cfg->zone_defaults = REALLOC2(0, 1, sizeof(*cfg->zone_defaults)); 19 | memset(cfg->zone_defaults, 0, sizeof(*cfg->zone_defaults)); 20 | 21 | /* Create a subsystem that keeps track of all the configuration files */ 22 | cfg->tf = conf_trackfile_create(); 23 | 24 | /* 25 | * Set some defaults 26 | */ 27 | cfg_load_string(cfg, "options { port 53; };"); 28 | 29 | assert(cfg->data_plane.port == 53); 30 | 31 | return cfg; 32 | } 33 | 34 | /**************************************************************************** 35 | ****************************************************************************/ 36 | void 37 | free2(char *str) 38 | { 39 | if (str) 40 | free(str); 41 | } 42 | 43 | /**************************************************************************** 44 | ****************************************************************************/ 45 | void cfg_destroy(struct Configuration *cfg) 46 | { 47 | if (cfg == NULL) 48 | return; 49 | 50 | free2(cfg->options.directory); 51 | free2(cfg->options.pid_file); 52 | free2(cfg->options.hostname); 53 | free2(cfg->options.server_id); 54 | free2(cfg->options.version); 55 | 56 | free(cfg); 57 | } 58 | 59 | 60 | int 61 | cfg_selftest(void) 62 | { 63 | struct Configuration *cfg; 64 | 65 | cfg = cfg_create(); 66 | 67 | cfg_load_string(cfg, "options {\n listen-on port 53 { any; { 127.0.0.1; ::1; }; }; };"); 68 | 69 | cfg_destroy(cfg); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /src/crypto-base64.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_BASE64_H 2 | #define CRYPTO_BASE64_H 3 | #include 4 | 5 | size_t base64_decode(void *dst, size_t sizeof_dst, const void *src, size_t sizeof_src); 6 | size_t base64_encode(void *dst, size_t sizeof_dst, const void *src, size_t sizeof_src); 7 | 8 | int base64_selftest(void); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/crypto-md5.h: -------------------------------------------------------------------------------- 1 | /* MD5 context. */ 2 | typedef struct { 3 | unsigned state[4]; /* state (ABCD) */ 4 | unsigned count[2]; /* number of bits, modulo 2^64 (lsb first) */ 5 | unsigned char buffer[64]; /* input buffer */ 6 | } MD5_CTX; 7 | 8 | void MD5Init(MD5_CTX *ctx); 9 | void MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen); 10 | void MD5Final(unsigned char digest[16], MD5_CTX *context); 11 | 12 | -------------------------------------------------------------------------------- /src/crypto-murmur3.h: -------------------------------------------------------------------------------- 1 | #ifndef MURMURHASH3_H_ 2 | #define MURMURHASH3_H_ 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | uint64_t murmurhash3(const void *key, size_t len, uint64_t seed); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /src/crypto-siphash.h: -------------------------------------------------------------------------------- 1 | #ifndef SIPHASH_H 2 | #define SIPHASH_H 1 3 | #include 4 | 5 | int siphash( unsigned char out[8], const unsigned char *in, unsigned long long inlen, const unsigned char k[16] ); 6 | uint64_t siphash_x(const unsigned char *in, unsigned long long inlen, uint64_t key1, uint64_t key2); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/db-entry.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_RECORD_H 2 | #define DB_RECORD_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include 8 | #include "zonefile-rr.h" 9 | 10 | struct DB_XDomain; 11 | struct DBEntry; 12 | 13 | void entry_create_self(struct DBEntry **p_record, const struct DB_XDomain *xdomain, unsigned zone_label_count, 14 | int type, unsigned ttl, unsigned rdlength, const unsigned char *rdata); 15 | const struct DBEntry *entry_find(const struct DBEntry *record, const struct DB_XDomain *xdomain, unsigned zone_label_count, unsigned name_label_count); 16 | 17 | unsigned entry_chain_length(const struct DBEntry *record); 18 | 19 | int entry_is_delegation(const struct DBEntry *record); 20 | 21 | struct DomainPointer entry_name(const struct DBEntry *record); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | #endif 27 | -------------------------------------------------------------------------------- /src/db-rrset.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_ENTRY_RR_H 2 | #define DB_ENTRY_RR_H 3 | 4 | struct DBrrset; 5 | struct DB_XDomain; 6 | struct DomainPointer; 7 | struct Packet; 8 | struct Compressor; 9 | struct DBEntry; 10 | struct DBZone; 11 | 12 | const struct DBrrset *rrset_first(const struct DBEntry *record, int type); 13 | const struct DBrrset *rrset_next(const struct DBEntry *record, int type, const struct DBrrset *rrset); 14 | const struct DBEntry *rrset_get_glue(const struct DBZone *zone, const struct DBEntry *record, const struct DBrrset *rrset, struct DomainPointer *name); 15 | void rrset_names_from_glue(const struct DBrrset *rrset, struct DomainPointer *name, struct DomainPointer *origin); 16 | unsigned rrset_packet_append(const struct DBrrset *rrset, struct Packet *pkt, struct Compressor *compressor, struct DomainPointer name, struct DomainPointer origin); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/db-xdomain.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_XDOMAIN_H 2 | #define DB_XDOMAIN_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | struct DomainPointer; 8 | 9 | struct DB_XDomain 10 | { 11 | uint64_t hash; 12 | unsigned label_count; 13 | struct { 14 | const unsigned char *name; 15 | uint64_t hash; 16 | } labels[127]; 17 | }; 18 | 19 | 20 | struct Domain; 21 | 22 | int xdomain_is_equal(const struct DB_XDomain *lhs, const struct DomainPointer *rhs, unsigned max_labels); 23 | void xdomain_copy(const struct DB_XDomain *lhs, struct DomainPointer *rhs); 24 | 25 | void xdomain_reverse2(struct DB_XDomain *result, const unsigned char *name, unsigned length); 26 | void xdomain_err(const struct DB_XDomain *domain, const char *fmt, ...); 27 | int xdomain_is_wildcard(const struct DB_XDomain *domain); 28 | uint64_t xdomain_label_hash(const struct DB_XDomain *xdomain, unsigned label_count); 29 | 30 | void xdomain_reverse3(struct DB_XDomain *result, const struct DomainPointer *prefix, const struct DomainPointer *suffix); 31 | 32 | 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #endif 38 | -------------------------------------------------------------------------------- /src/db-zone.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_ZONE_H 2 | #define DB_ZONE_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include "zonefile-rr.h" 8 | 9 | 10 | struct DBZone; 11 | struct DB_XDomain; 12 | struct Source; 13 | struct DomainPointer; 14 | 15 | struct DBZone *zone_create_self( 16 | const struct DB_XDomain *xdomain, 17 | uint64_t filesize, 18 | const char *filename); 19 | 20 | void zone_create_record( 21 | struct DBZone *zone, 22 | const struct DB_XDomain *xdomain, 23 | unsigned type, 24 | unsigned ttl, 25 | unsigned rdlength, 26 | const unsigned char *rdata); 27 | void zone_create_record2(struct DBZone *zone, 28 | struct DomainPointer domain, 29 | struct DomainPointer origin, 30 | unsigned type, 31 | unsigned ttl, 32 | unsigned rdlength, 33 | const unsigned char *rdata 34 | ); 35 | struct DBZone *zone_follow_chain(struct DBZone *zone, const struct DB_XDomain *xdomain, unsigned max_labels); 36 | const struct DBEntry *zone_lookup_exact(const struct DBZone *zone, const struct DB_XDomain *xdomain); 37 | const struct DBEntry *zone_lookup_exact2(const struct DBZone *zone, const unsigned char *name, unsigned length); 38 | const struct DBEntry *zone_lookup_wildcard(const struct DBZone *zone, const struct DB_XDomain *xdomain); 39 | const struct DBEntry *zone_lookup_delegation(const struct DBZone *zone, const struct DB_XDomain *xdomain); 40 | const struct DBEntry *zone_lookup_delegation2(const struct DBZone *zone, struct DomainPointer domain); 41 | 42 | const struct DBrrset *zone_get_soa_rr(const struct DBZone *zone); 43 | void zone_name_from_record(const struct DBZone *zone, const struct DBEntry *record, struct DomainPointer *name, struct DomainPointer *origin); 44 | void zone_name(const struct DBZone *zone, struct DomainPointer *origin); 45 | uint64_t zone_hash(const struct DBZone *zone); 46 | struct DBZone *zone_next(struct DBZone *zone); 47 | void zone_insert_self(struct DBZone *zone, volatile struct DBZone **next); 48 | 49 | const struct DBEntry *zone_entry_by_index(const struct DBZone *zone, unsigned i); 50 | 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | #endif 56 | -------------------------------------------------------------------------------- /src/db.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_H 2 | #define DB_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include 8 | #include 9 | #include "domainname.h" 10 | struct Source; 11 | struct Catalog; 12 | 13 | /** 14 | * Create a new/empty DNS database with no zones or names. 15 | */ 16 | struct Catalog *catalog_create(); 17 | 18 | /** 19 | * Reset the hashtable for the zones, in case we are holding 20 | * thousands instead of hundreds 21 | */ 22 | void 23 | catalog_reset_zonecount(struct Catalog *db, unsigned new_count); 24 | 25 | 26 | /** 27 | * Free all the memory used in the DNS database, including 28 | * the individual zones. 29 | * 30 | * @param db 31 | * A catalog created by a call to "catalog_create()" 32 | */ 33 | void catalog_destroy(struct Catalog *db); 34 | 35 | /** 36 | * Creates a "zone" fomr an SOA RR record. This is a special insertion event 37 | * unlike all other normal RRs, because it creates a new zone rather than 38 | * inserting information into a zone. 39 | * 40 | * @param catalog 41 | * A database created with a call to 'catalog_create()' 42 | * @param xdomain 43 | * The domain-name of the zone 44 | * @param filesize 45 | * A hint about the size of the file containing the zone. We use this 46 | * hint in order to initialize an appropriately sized hash-table. 47 | * If this hint is wrong, and we need to, we'll grow the size of the 48 | * table 49 | * @return 50 | * a pointer to the newly created zone, or NULL if an error occurred. 51 | */ 52 | const struct DBZone * 53 | catalog_create_zone( 54 | struct Catalog *catalog, 55 | const struct DB_XDomain *xdomain, 56 | uint64_t filesize, 57 | const char *filename 58 | ); 59 | 60 | /* called with an SOA record to create a zone */ 61 | const struct DBZone * 62 | catalog_create_zone2(struct Catalog *db, 63 | struct DomainPointer domain, struct DomainPointer origin, 64 | uint64_t filesize, const char *filename); 65 | 66 | 67 | 68 | /* "longest suffix" search for best matching zone */ 69 | struct DBZone * 70 | catalog_lookup_zone( 71 | const struct Catalog *db, 72 | const struct DB_XDomain *xdomain 73 | ); 74 | struct DBZone * 75 | catalog_lookup_zone2( 76 | struct Catalog *db, 77 | struct DomainPointer prefix, 78 | struct DomainPointer suffix 79 | ); 80 | 81 | /** 82 | * Counts the number of zones that have been created. This can be called 83 | * after parsing zone-files to see if any have been successfully parsed. 84 | * 85 | * @param catalog 86 | * A database containing zones and domains. 87 | * @return 88 | * the total number of zones that have been created. 89 | */ 90 | unsigned 91 | catalog_zone_count(const struct Catalog *catalog); 92 | 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | #endif 98 | -------------------------------------------------------------------------------- /src/domainname.h: -------------------------------------------------------------------------------- 1 | #ifndef DOMAINNAME_H 2 | #define DOMAINNAME_H 3 | #include "db-xdomain.h" 4 | extern struct DomainPointer ROOT; 5 | 6 | struct DomainPointer 7 | { 8 | const unsigned char *name; 9 | unsigned length; 10 | }; 11 | struct Domainasdfasf 12 | { 13 | unsigned char length; 14 | unsigned char is_absolute; 15 | unsigned char label; 16 | unsigned char *name; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/extract.h: -------------------------------------------------------------------------------- 1 | /* Copyright: (c) 2009-2010 by Robert David Graham 2 | ** License: This code is private to the author, and you do not 3 | ** have a license to run it, or own a copy, unless given 4 | ** a license personally by the author. This is 5 | ** explained in the LICENSE file at the root of the project. 6 | **/ 7 | #ifndef EXTRACT_H 8 | #define EXTRACT_H 9 | 10 | #define ex32be(px) ( *((unsigned char*)(px)+0)<<24 \ 11 | | *((unsigned char*)(px)+1)<<16 \ 12 | | *((unsigned char*)(px)+2)<< 8 \ 13 | | *((unsigned char*)(px)+3)<< 0 ) 14 | #define ex32le(px) ( *((unsigned char*)(px)+0)<< 0 \ 15 | | *((unsigned char*)(px)+1)<< 8 \ 16 | | *((unsigned char*)(px)+2)<<16 \ 17 | | *((unsigned char*)(px)+3)<<24 ) 18 | #define ex16be(px) ( *((unsigned char*)(px)+0)<< 8 \ 19 | | *((unsigned char*)(px)+1)<< 0 ) 20 | #define ex16le(px) ( *((unsigned char*)(px)+0)<< 0 \ 21 | | *((unsigned char*)(px)+1)<< 8 ) 22 | 23 | #define ex24be(px) ( *((unsigned char*)(px)+0)<<16 \ 24 | | *((unsigned char*)(px)+1)<< 8 \ 25 | | *((unsigned char*)(px)+2)<< 0 ) 26 | #define ex24le(px) ( *((unsigned char*)(px)+0)<< 0 \ 27 | | *((unsigned char*)(px)+1)<< 8 \ 28 | | *((unsigned char*)(px)+2)<<16 ) 29 | 30 | #define ex64be(px) ( (((uint64_t)ex32be(px))<<32L) + ((uint64_t)ex32be((px)+4)) ) 31 | #define ex64le(px) ( ((uint64_t)ex32be(px)) + (((uint64_t)ex32be((px)+4))<<32L) ) 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/grind-config.c: -------------------------------------------------------------------------------- 1 | #include "grind.h" 2 | #include "unusedparm.h" 3 | 4 | int grind_load_configuration(struct Grind *grind, const char *filename) 5 | { 6 | UNUSEDPARM(grind); 7 | UNUSEDPARM(filename); 8 | return Failure; 9 | } 10 | -------------------------------------------------------------------------------- /src/grind.h: -------------------------------------------------------------------------------- 1 | #ifndef GRIND_H 2 | #define GRIND_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include "success-failure.h" 8 | #include "domainname.h" 9 | 10 | struct Grind; 11 | struct Domain; 12 | 13 | struct Grind *grind_create(); 14 | void grind_destroy(struct Grind *grind); 15 | 16 | int grind_load_zonefile(struct Grind *grind, const char *zonefilename, struct DomainPointer origin, uint64_t ttl); 17 | 18 | int grind_load_configuration(struct Grind *grind, const char *filename); 19 | 20 | struct Catalog *grind_get_catalog(struct Grind *grind); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | #endif 26 | -------------------------------------------------------------------------------- /src/logger.c: -------------------------------------------------------------------------------- 1 | /* 2 | log messages to console, depending on verbose level 3 | 4 | Use -v (or -d) to get more verbose output. The more -v you add, the 5 | more verbose the output becomes. 6 | 7 | Details about the running of the program go to . 8 | Details about scan results go to , so that they can easily 9 | be redirected to a file. 10 | */ 11 | #include "logger.h" 12 | #include "string_s.h" 13 | #include 14 | #include 15 | 16 | int verbosity = 0; /* yea! a global variable!! */ 17 | 18 | 19 | /*************************************************************************** 20 | ***************************************************************************/ 21 | void 22 | vLOG(enum LogLevel level, enum LogCategory cat, const char *fmt, va_list marker) 23 | { 24 | vfprintf(stderr, fmt, marker); 25 | fflush(stderr); 26 | } 27 | 28 | 29 | void LOG_CRIT(enum LogCategory cat, const char *fmt, ...) 30 | { 31 | va_list marker; 32 | 33 | va_start(marker, fmt); 34 | vLOG(L_CRIT, cat, fmt, marker); 35 | va_end(marker); 36 | } 37 | 38 | void LOG_ERR(enum LogCategory cat, const char *fmt, ...) 39 | { 40 | va_list marker; 41 | 42 | va_start(marker, fmt); 43 | vLOG(L_ERR, cat, fmt, marker); 44 | va_end(marker); 45 | } 46 | 47 | void LOG_WARN(enum LogCategory cat, const char *fmt, ...) 48 | { 49 | va_list marker; 50 | 51 | va_start(marker, fmt); 52 | vLOG(L_WARN, cat, fmt, marker); 53 | va_end(marker); 54 | } 55 | 56 | void LOG_INFO(enum LogCategory cat, const char *fmt, ...) 57 | { 58 | va_list marker; 59 | 60 | va_start(marker, fmt); 61 | vLOG(L_INFO, cat, fmt, marker); 62 | va_end(marker); 63 | } 64 | 65 | void LOG_DBG(enum LogCategory cat, int debug_level, const char *fmt, ...) 66 | { 67 | va_list marker; 68 | 69 | if (debug_level >= verbosity) 70 | return; 71 | va_start(marker, fmt); 72 | vLOG(L_DBG0, cat, fmt, marker); 73 | va_end(marker); 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | 4 | extern int verbosity; /* defined in logger.c */ 5 | 6 | enum LogLevel { 7 | L_CRIT, /* "critical" */ 8 | L_ERR, /* "error" */ 9 | L_WARN, /* "warning" */ 10 | L_NOTE, /* "notice" */ 11 | L_INFO, /* "info" */ 12 | L_DBG0, 13 | L_DBG1, 14 | L_DBG2, 15 | L_DBG3, 16 | L_DYNAMIC=L_DBG0+100, 17 | }; 18 | 19 | enum LogCategory { 20 | C_ZONEFILE, /* errors parsing zonefiles */ 21 | C_CLIENT, 22 | C_CONFIG, 23 | C_DATABASE, 24 | C_DNSSEC, 25 | C_GENERAL, /* anything not in another category */ 26 | C_NETWORK, 27 | C_NOTIFY, /* all NOTIFY operations */ 28 | C_QUERIES, 29 | C_RATE_LIMIT, 30 | C_SECURITY, /* approval and denial of requests */ 31 | C_UPDATE, /* all UPDATE dyn-DNS operations */ 32 | C_UPDATE_SECURITY, /* approval and denial of UPDATE requests with dyn-DNS */ 33 | C_XFER_IN, /* zone transfers the server is receiving */ 34 | C_XFER_OUT, /* zone transfers the server is sending */ 35 | }; 36 | 37 | //void LOG(enum LogLevel lvl, enum LogCategory cat, const char *fmt, ...); 38 | 39 | void LOG_CRIT(enum LogCategory cat, const char *fmt, ...); 40 | void LOG_ERR(enum LogCategory cat, const char *fmt, ...); 41 | void LOG_WARN(enum LogCategory cat, const char *fmt, ...); 42 | void LOG_INFO(enum LogCategory cat, const char *fmt, ...); 43 | void LOG_DBG(enum LogCategory cat, int debug_level, const char *fmt, ...); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGING_H 2 | #define LOGGING_H 3 | 4 | 5 | #endif 6 | -------------------------------------------------------------------------------- /src/main-checkconf.c: -------------------------------------------------------------------------------- 1 | #include "configuration.h" 2 | #include 3 | #include 4 | #include 5 | 6 | const char *version; 7 | 8 | struct Checkconf 9 | { 10 | unsigned is_print_filenames; 11 | unsigned is_checkzone; 12 | unsigned is_checkzone_journal; 13 | const char *filename; 14 | }; 15 | 16 | static void 17 | parse_command_line(struct Checkconf *check, int argc, char *argv[]) 18 | { 19 | int i; 20 | 21 | for (i=1; iis_print_filenames = 1; 32 | break; 33 | case 'v': 34 | fprintf(stderr, "%s\n", version); 35 | exit(1); 36 | break; 37 | case 'z': 38 | check->is_checkzone = 1; 39 | break; 40 | case 'j': 41 | check->is_checkzone_journal = 1; 42 | break; 43 | } else { 44 | if (check->filename != 0) { 45 | fprintf(stderr, "only one configuration filename may be specified\n"); 46 | exit(1); 47 | } 48 | check->filename = argv[i]; 49 | } 50 | } 51 | 52 | if (check->filename == 0) { 53 | fprintf(stderr, "at least one filename must be specified\n"); 54 | exit(1); 55 | } 56 | } 57 | 58 | int checkconf(int argc, char *argv[]) 59 | { 60 | struct Checkconf check; 61 | struct Configuration *cfg; 62 | 63 | memset(&check, 0, sizeof(check)); 64 | 65 | parse_command_line(&check, argc, argv); 66 | 67 | cfg = cfg_create(); 68 | cfg_parse_file(cfg, check.filename); 69 | 70 | cfg_destroy(cfg); 71 | return 0; 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/main-checkzone.c: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 2 | #include "db.h" 3 | #include "domainname.h" 4 | #include "zonefile-parse.h" 5 | #include "zonefile-load.h" 6 | #include "zonefile-tracker.h" 7 | #include "string_s.h" 8 | #include "success-failure.h" 9 | #include 10 | 11 | 12 | static const struct DomainPointer root = {(const unsigned char*)"\0",1}; 13 | 14 | struct ZoneCheck 15 | { 16 | struct Catalog *db; 17 | 18 | }; 19 | 20 | extern uint64_t entry_bytes; 21 | extern uint64_t entry_count; 22 | extern uint64_t total_chain_length; 23 | 24 | int checkzone(int argc, char *argv[]) 25 | { 26 | clock_t start, stop; 27 | struct ZoneCheck zonecheck[1]; 28 | int i; 29 | 30 | 31 | zonecheck->db = catalog_create(); 32 | 33 | start = clock(); 34 | for (i=2; idb, 54 | 0 55 | ); 56 | 57 | for (;;) { 58 | unsigned char buf[65536]; 59 | size_t bytes_read; 60 | 61 | bytes_read = fread((char*)buf, 1, sizeof(buf), fp); 62 | if (bytes_read == 0) 63 | break; 64 | 65 | zonefile_parse( 66 | parser, 67 | buf, 68 | bytes_read 69 | ); 70 | 71 | tracker_report(tracker, bytes_read); 72 | } 73 | 74 | if (zonefile_end(parser) == Success) { 75 | fprintf(stderr, "%s: success\n", filename); 76 | } else { 77 | fprintf(stderr, "%s: failure\n", filename); 78 | } 79 | } 80 | 81 | stop = clock(); 82 | { 83 | double ellapsed = 1.0*(stop-start)/CLOCKS_PER_SEC; 84 | printf("ellapsed = %f-sec\n", ellapsed); 85 | if (entry_count) { 86 | double avg_chain_len = (1.0*total_chain_length)/entry_count; 87 | printf(" %" PRIu64 "-entries, %" PRIu64 "-bytes, %" PRIu64 "-avg, %f-chain\n", 88 | entry_count, 89 | entry_bytes, 90 | entry_bytes/entry_count, 91 | avg_chain_len); 92 | } 93 | 94 | } 95 | 96 | return Success; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/main-conf.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_CONF_H 2 | #define MAIN_CONF_H 3 | #include 4 | #include "adapter.h" 5 | #include "configuration-adapter.h" 6 | 7 | struct Configuration; 8 | 9 | struct CoreSocketSet 10 | { 11 | struct CoreSocketItem *list; 12 | size_t count; 13 | }; 14 | 15 | struct RawFlags 16 | { 17 | unsigned is_pfring:1; 18 | unsigned is_sendq:1; 19 | unsigned is_packet_trace:1; 20 | unsigned is_offline:1; 21 | }; 22 | 23 | struct RawItem 24 | { 25 | char ifname[256]; 26 | struct Adapter *adapter; 27 | unsigned adapter_ip; 28 | unsigned char adapter_ipv6[16]; 29 | unsigned adapter_port; 30 | unsigned char adapter_mac[6]; 31 | unsigned char router_mac[6]; 32 | }; 33 | 34 | struct RawSet 35 | { 36 | struct RawItem *list; 37 | size_t count; 38 | }; 39 | 40 | 41 | struct CoreWorkerThread 42 | { 43 | /* [SYNCHRONIZATION POINT] 44 | */ 45 | volatile size_t loop_count; 46 | 47 | /** Pointer back to the parent system */ 48 | struct Core *core; 49 | 50 | /** A number starting at zero up to the number of threads we have in 51 | * the system. This is so that we can do specific things to threads, 52 | * such as forcing a thread with a certain index to run on a certain 53 | * CPU core. */ 54 | unsigned index; 55 | 56 | /** This is the operating-system handle for this thread. This 57 | * will be used by the "join" function to wait for thread 58 | * termination */ 59 | size_t handle; 60 | 61 | /** 62 | * Set by the config-thread telling this worker-thread that it's 63 | * time to cleanup and exit */ 64 | volatile unsigned should_end; 65 | 66 | }; 67 | 68 | struct Core 69 | { 70 | /** We are loading changes/updates to zone information in the 71 | * control-plane. */ 72 | struct Catalog *db_load; 73 | 74 | /** Where we are serving queries from the data-plane. Changes 75 | * can only be replaced from the control-threads using the RCU 76 | * method */ 77 | struct Catalog *db_run; 78 | 79 | 80 | /** 81 | * the set of raw-sockets that the data-plane threads are using 82 | */ 83 | volatile struct RawSet *raw_run; 84 | 85 | /** 86 | * The set of Sockets that the data-plane run threads are using. 87 | * During a reconfiguration event, these sockets can change 88 | */ 89 | volatile struct CoreSocketSet *socket_run; 90 | 91 | /** 92 | * These are the data-plane worker-threads that process queries from 93 | * the network. Note that there are other types of worker threads for 94 | * parsing zonefiles and inserting records into databases, but this 95 | * is the classic 'worker' for DNS servers, so we use that name here. */ 96 | struct CoreWorkerThread **workers; 97 | unsigned workers_count; 98 | 99 | 100 | unsigned is_pfring:1; 101 | unsigned is_sendq:1; 102 | unsigned is_offline:1; 103 | unsigned is_packet_trace:1; 104 | unsigned is_zonefile_check:1; 105 | }; 106 | 107 | /** 108 | * Initialize a configuration structure 109 | */ 110 | void core_init(struct Core *conf); 111 | 112 | /** 113 | * Read configuration information from a file 114 | */ 115 | void conf_read_config_file(struct Core *conf, const char *filename); 116 | 117 | /** 118 | * Read configuration information from the command-line 119 | */ 120 | void conf_command_line(struct Configuration *cfg, int argc, char *argv[]); 121 | 122 | /** 123 | * Once all configuration information has been read, then 124 | * read in all the zonefiles 125 | */ 126 | enum SuccessFailure 127 | conf_zonefiles_parse( struct Catalog *db_load, 128 | struct Configuration *cfg, 129 | uint64_t *total_files, 130 | uint64_t *total_bytes); 131 | 132 | 133 | /** 134 | * Change the number of data-plane worker-threads 135 | */ 136 | void change_resolver_threads(struct Core *core, struct Configuration *cfg_new); 137 | 138 | 139 | /** 140 | * Chagne the data-plane sockets 141 | */ 142 | void change_worker_sockets(struct Core *core, struct Configuration *cfg_new, struct Configuration *cfg_old); 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /src/main-regression.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_REGRESSION_H 2 | #define MAIN_REGRESSION_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | int regression_test(const char *directory_name); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif 12 | #endif 13 | -------------------------------------------------------------------------------- /src/main-server-socket.c: -------------------------------------------------------------------------------- 1 | #include "main-conf.h" 2 | #include "db.h" 3 | #include "logger.h" 4 | #include "main-server-socket.h" 5 | #include 6 | #include 7 | #include "string_s.h" 8 | #include "proto-dns.h" 9 | #include "proto-dns-compressor.h" 10 | #include "proto-dns-formatter.h" 11 | #include "resolver.h" 12 | 13 | #include "pixie-sockets.h" 14 | 15 | /****************************************************************************** 16 | * This is the mail loop when running over sockets, receiving packets and 17 | * sending responses. 18 | ******************************************************************************/ 19 | void 20 | sockets_thread(struct Core *core) 21 | { 22 | int err; 23 | SOCKET fd; 24 | struct sockaddr_in6 sin; 25 | static const unsigned port = 53; 26 | 27 | /* 28 | * This software obtains its speed by bypassing the operating system 29 | * stack. Thus, running on top of 'sockets' is going to be a lot 30 | * slower 31 | */ 32 | fprintf(stderr, "WARNING: running in slow 'sockets' mode\n"); 33 | 34 | 35 | /* 36 | * Legacy Windows is legacy. 37 | */ 38 | #if defined(WIN32) 39 | {WSADATA x; if (WSAStartup(0x201, &x)) exit(1);} 40 | #endif 41 | 42 | /* 43 | * Create a socket for incoming UDP packets. By specifying IPv6, we are 44 | * actually going to allow both IPv4 and IPv6. 45 | */ 46 | fd = socket(AF_INET6, SOCK_DGRAM, 0); 47 | if (fd <= 0) { 48 | LOG_ERR(C_NETWORK, "FAIL: couldn't create socket %u\n", WSAGetLastError()); 49 | return; 50 | } 51 | 52 | /* 53 | * Set the 'reuse' feature of the socket, otherwise restarting the process 54 | * requires a wait before binding back to the same port number 55 | */ 56 | { 57 | int on = 1; 58 | err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,sizeof(on)); 59 | if (err < 0) { 60 | perror("setsockopt(SO_REUSEADDR) failed"); 61 | exit(1); 62 | } 63 | } 64 | 65 | /* 66 | * Enable both IPv4 and IPv6 to be used on the same sockets. This appears to 67 | * be needed for Windows, but not needed for Mac OS X. 68 | */ 69 | #ifdef IPV6_V6ONLY 70 | { 71 | int on = 0; 72 | err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); 73 | if (err < 0) { 74 | perror("setsockopt(IPV6_V6ONLY) failed"); 75 | exit(1); 76 | } 77 | } 78 | #endif 79 | 80 | 81 | /* 82 | * Listen on any IPv4 or IPv6 address in the system 83 | */ 84 | memset(&sin, 0, sizeof(sin)); 85 | sin.sin6_family = AF_INET6; 86 | sin.sin6_addr = in6addr_any; 87 | sin.sin6_port = htons(port); 88 | err = bind(fd, (struct sockaddr*)&sin, sizeof(sin)); 89 | if (err) { 90 | switch (WSAGetLastError()) { 91 | case WSA(EACCES): 92 | LOG_ERR(C_NETWORK, "FAIL: couldn't bind to port %u: %s\n", port, 93 | "access denied"); 94 | if (port <= 1024) 95 | LOG_ERR(C_NETWORK, " hint... need to be root for ports below 1024\n"); 96 | break; 97 | case WSA(EADDRINUSE): 98 | LOG_ERR(C_NETWORK, "FAIL: couldn't bind to port %u: %s\n", port, 99 | "address in use"); 100 | LOG_ERR(C_NETWORK, " hint... some other server is running on that port\n"); 101 | break; 102 | default: 103 | LOG_ERR(C_NETWORK, "FAIL: couldn't bind to port %u: %u\n", port, 104 | WSAGetLastError()); 105 | } 106 | exit(1); 107 | } else { 108 | LOG_INFO(C_NETWORK, "UDP port: %u\n", port); 109 | } 110 | 111 | /* 112 | * Sit in loop processing incoming UDP packets 113 | */ 114 | for (;;) { 115 | unsigned char buf[2048]; 116 | int bytes_received; 117 | socklen_t sizeof_sin = sizeof(sin); 118 | struct DNS_Incoming request[1]; 119 | struct DNS_OutgoingResponse response[1]; 120 | struct Packet pkt; 121 | unsigned char buf2[2048]; 122 | 123 | /* 124 | * 1. receive 'packet' 125 | */ 126 | bytes_received = recvfrom(fd, 127 | (char*)buf, sizeof(buf), 128 | 0, 129 | (struct sockaddr*)&sin, &sizeof_sin); 130 | if (bytes_received == 0) 131 | continue; 132 | 133 | 134 | /* 135 | * 2. parse 'packet' into a 'request' 136 | */ 137 | proto_dns_parse(request, buf, 0, bytes_received); 138 | if (!request->is_valid) 139 | continue; 140 | 141 | 142 | /* 143 | * 3. resolve 'request' into a 'repsonse' 144 | */ 145 | resolver_init(response, 146 | request->query_name.name, 147 | request->query_name.length, 148 | request->query_type, 149 | request->id, 150 | request->opcode); 151 | 152 | resolver_algorithm(core->db_run, response, request); 153 | 154 | 155 | /* 156 | * 4. format the 'response' into a 'packet' 157 | */ 158 | pkt.buf = buf2; 159 | pkt.max = sizeof(buf2); 160 | pkt.offset = 0; 161 | dns_format_response(response, &pkt); 162 | 163 | /* 164 | * 5. Transmit the 'packet' 165 | */ 166 | if (pkt.offset < pkt.max) { 167 | sendto(fd, 168 | (char*)pkt.buf, pkt.offset, 0, 169 | (struct sockaddr*)&sin, 170 | sizeof_sin); 171 | } 172 | } 173 | } 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/main-server-socket.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_SERVER_SOCKET_H 2 | #define MAIN_SERVER_SOCKET_H 3 | 4 | 5 | void 6 | sockets_thread(struct Core *conf); 7 | 8 | #endif 9 | 10 | -------------------------------------------------------------------------------- /src/main-thread.c: -------------------------------------------------------------------------------- 1 | #include "main-thread.h" 2 | #include "rawsock.h" 3 | #include "network.h" 4 | #include "thread.h" 5 | #include "adapter.h" 6 | #include "util-realloc2.h" 7 | #include 8 | 9 | #define PACKET_SIZE 1514 10 | 11 | 12 | /****************************************************************************** 13 | ******************************************************************************/ 14 | static struct Packet 15 | alloc_packet(struct Adapter *adapter, struct Thread *thread) 16 | { 17 | struct Packet pkt; 18 | pkt.buf = thread->userdata; 19 | pkt.offset = 0; 20 | pkt.max = PACKET_SIZE; 21 | pkt.fixup.network = 0; 22 | pkt.fixup.transport = 0; 23 | 24 | return pkt; 25 | } 26 | 27 | 28 | 29 | /****************************************************************************** 30 | ******************************************************************************/ 31 | void main_thread(void *v) 32 | { 33 | struct ThreadParms *parms = (struct ThreadParms *)v; 34 | struct Adapter *adapter = parms->adapter; 35 | struct Frame frame[1]; 36 | struct Thread thread[1]; 37 | 38 | memset(frame, 0, sizeof(frame[0])); 39 | 40 | /* 41 | * thread 42 | */ 43 | memset(thread, 0, sizeof(thread[0])); 44 | thread->catalog_run = parms->catalog_run; 45 | thread->userdata = (char*)MALLOC2(PACKET_SIZE); 46 | 47 | adapter->alloc_packet = alloc_packet; 48 | adapter->xmit_packet = rawsock_send_packet; 49 | 50 | 51 | for (;;) { 52 | int err; 53 | unsigned length; 54 | unsigned secs; 55 | unsigned usecs; 56 | const unsigned char *px; 57 | 58 | err = rawsock_recv_packet( 59 | adapter, 60 | &length, 61 | &secs, 62 | &usecs, 63 | &px); 64 | 65 | if (err != 0) 66 | continue; 67 | 68 | network_receive( 69 | frame, 70 | thread, 71 | adapter, 72 | secs, 73 | usecs, 74 | px, 75 | length); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/main-thread.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_THREAD_H 2 | #define MAIN_THREAD_H 3 | 4 | void main_thread(void *parms); 5 | 6 | struct ThreadParms 7 | { 8 | unsigned nic_index; 9 | unsigned adapter_ip; 10 | unsigned char adapter_mac[6]; 11 | struct Adapter *adapter; 12 | 13 | struct Catalog *catalog_run; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "grind.h" 2 | #include "logger.h" 3 | #include "main-regression.h" 4 | #include "selftest.h" 5 | #include "adapter-pcaplive.h" 6 | #include "zonefile-parse.h" 7 | #include "rawsock.h" 8 | #include "configuration.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | int is_verbose; 16 | 17 | const char *version = "robdns/0.2"; 18 | 19 | /* temporary 20 | * These globals are for printing debug messages. They are global for now, but 21 | * I'll get rid of them eventually 22 | */ 23 | uint64_t entry_bytes; 24 | uint64_t entry_count; 25 | uint64_t total_chain_length; 26 | 27 | 28 | int checkconf(int argc, char *argv[]); 29 | int checkzone(int argc, char *argv[]); 30 | int listif(int argc, char *argv[]); 31 | int foreground(int argc, char *argv[]); 32 | int pcap2zone(int argc, char *argv[]); 33 | int selftest2(int argc, char *argv[]); 34 | int perftest(int argc, char *argv[]); 35 | 36 | /**************************************************************************** 37 | ****************************************************************************/ 38 | struct { 39 | const char *name; 40 | int (*func)(int argc, char *argv[]); 41 | } commands[] = { 42 | 43 | {"selftest", selftest}, 44 | {"--selftest", selftest}, 45 | {"perftest", perftest}, 46 | {"--perftest", perftest}, 47 | {"regress", selftest}, 48 | {"--regress", selftest}, 49 | {"selftest2", selftest2}, 50 | {"checkzone", checkzone}, 51 | {"--checkzone", checkzone}, 52 | {"checkconf", checkconf}, 53 | {"--checkconf", checkconf}, 54 | {"listif", listif}, 55 | {"foreground", foreground}, 56 | {"pcap2zone", pcap2zone}, 57 | {0,0} 58 | }; 59 | 60 | 61 | /**************************************************************************** 62 | ****************************************************************************/ 63 | int 64 | main(int argc, char *argv[]) 65 | { 66 | int i; 67 | 68 | LOG_INFO(C_GENERAL, "--- Rob's DNS server v0.2 ----\n"); 69 | 70 | /* 71 | * Initialize various things that are process-wide. 72 | */ 73 | zonefile_parser_init(); 74 | cfg_parser_init(); 75 | rawsock_init(); 76 | 77 | /* 78 | * If nothing on command-line, print usage, then self-test for good 79 | * measure, then exit 80 | */ 81 | if (argc <= 1) { 82 | int return_code; 83 | 84 | /* first self-test, for the heck of it */ 85 | return_code = selftest(argc, argv); 86 | 87 | fprintf(stderr, "error: no command-line parameters specified\n"); 88 | fprintf(stderr, "\n"); 89 | fprintf(stderr, "usage:\n"); 90 | fprintf(stderr, " robdns \n"); 91 | fprintf(stderr, "where:\n"); 92 | fprintf(stderr, " contains DNs zone data (like \"example.zone\")\n"); 93 | fprintf(stderr, " is a configuration file (like \"named.conf\")\n"); 94 | 95 | return return_code; 96 | } 97 | 98 | 99 | /* 100 | * Look for a specific "command". This runs the program in a special way 101 | * that focuses on a particular area. For example, the "dig" command 102 | * behaves a lot like the BIND9 "dig" utility, but using our paradigm. 103 | */ 104 | for (i=0; commands[i].name; i++) { 105 | if (strcmp(commands[i].name, argv[1]) == 0) { 106 | int result; 107 | result = commands[i].func(argc, argv); 108 | if (result == Success) 109 | return 0; 110 | else 111 | return 1; 112 | } 113 | } 114 | 115 | 116 | /* 117 | * If no specific command was given, then run in the default mode as 118 | * a DNS server. This runs in the 'foreground' printing to stdout/stderr, 119 | * some other tool is needed to launch this as a service. 120 | */ 121 | foreground(argc, argv); 122 | 123 | return 0; 124 | 125 | 126 | /* 127 | * Temporary: check hash efficiency 128 | */ 129 | #if 0 130 | check_chain_lengths(grind); 131 | #endif 132 | 133 | 134 | #if 0 135 | struct Thread thread[1]; 136 | pcap_t *h; 137 | char errbuf[PCAP_ERRBUF_SIZE]; 138 | const char *if_name = name_from_address(argv[1]); 139 | 140 | 141 | memset(thread, 0, sizeof(thread[0])); 142 | thread->grind = grind; 143 | 144 | grind->ip_address = 0x0a141e0f; 145 | memcpy(grind->mac_address, "\x00\x11\x11\x22\x22\x22", 6); 146 | 147 | fprintf(stderr, "IP: %u.%u.%u.%u\n", 148 | (unsigned char)(grind->ip_address>>24), 149 | (unsigned char)(grind->ip_address>>16), 150 | (unsigned char)(grind->ip_address>> 8), 151 | (unsigned char)(grind->ip_address>> 0) 152 | ); 153 | fprintf(stderr, "MAC: %02x-%02x-%02x-%02x-%02x-%02x\n", 154 | grind->mac_address[0], 155 | grind->mac_address[1], 156 | grind->mac_address[2], 157 | grind->mac_address[3], 158 | grind->mac_address[4], 159 | grind->mac_address[5] 160 | ); 161 | 162 | 163 | /* 164 | * Open the PCAP adapter 165 | */ 166 | h = pcap_open_live( if_name, /* interface name */ 167 | 2048, /* packet size (snap length) = 2048 bytes */ 168 | 0, /* not promiscuous mode */ 169 | 1, /* 1-millisecond read timeout */ 170 | errbuf /* where to store error msgs */ 171 | ); 172 | if (h == NULL) { 173 | fprintf(stderr, "pcap_open_live(): %s\n", errbuf); 174 | return 0; 175 | } else { 176 | fprintf(stderr, "Adapter: %s\n", if_name); 177 | grind->adapter = h; 178 | } 179 | 180 | for (;;) { 181 | int x; 182 | 183 | x = pcap_dispatch( 184 | h, 185 | 1, 186 | stack_receive, 187 | (unsigned char *)thread); 188 | 189 | if (x == -1) 190 | break; 191 | } 192 | #endif 193 | } 194 | 195 | -------------------------------------------------------------------------------- /src/network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWRK_H 2 | #define NETWRK_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include 8 | #include "packet.h" 9 | #include "proto-dns.h" 10 | 11 | struct Catalog; 12 | 13 | struct ARP_IncomingRequest 14 | { 15 | unsigned is_valid; 16 | unsigned opcode; 17 | unsigned hardware_type; 18 | unsigned protocol_type; 19 | unsigned hardware_length; 20 | unsigned protocol_length; 21 | unsigned ip_src; 22 | unsigned ip_dst; 23 | const unsigned char *mac_src; 24 | const unsigned char *mac_dst; 25 | }; 26 | 27 | struct ICMP_IncomingRequest 28 | { 29 | unsigned is_valid:1; 30 | unsigned is_checksum_checked:1; 31 | unsigned is_checksum_valid:1; 32 | unsigned type; 33 | unsigned code; 34 | unsigned payload_length; 35 | unsigned original_checksum; 36 | const unsigned char *payload; 37 | }; 38 | 39 | 40 | struct Frame 41 | { 42 | struct Adapter *adapter; 43 | struct Thread *thread; 44 | int net_protocol; 45 | const unsigned char *mac_src; 46 | const unsigned char *mac_dst; 47 | unsigned ethertype; 48 | unsigned secs; 49 | unsigned usecs; 50 | unsigned ip_ver; 51 | unsigned ip_src; 52 | unsigned ip_dst; 53 | unsigned ip_checksum_is_valid:1; 54 | unsigned port_src; 55 | unsigned port_dst; 56 | unsigned time_secs; 57 | unsigned time_usecs; 58 | struct DNS_Incoming dns[1]; 59 | struct ARP_IncomingRequest arp[1]; 60 | struct ICMP_IncomingRequest icmp[1]; 61 | }; 62 | 63 | enum { 64 | NET_NOTHING, 65 | NET_ETHERNET, 66 | NET_ARP, 67 | NET_IP, 68 | NET_ICMP, 69 | NET_UDP, 70 | NET_TCP, 71 | NET_DNS, 72 | }; 73 | 74 | 75 | /* Create a response packet going the other way. There MUST be a matching 76 | * call to frame_xmit_response() to free resources */ 77 | struct Packet frame_create_response(struct Frame *frame, int protocol); 78 | 79 | /* Transmit packet allocated by frame_create_response(). Set 'buf-length' to 80 | * zero to drop packet without sending it */ 81 | void frame_xmit_response(struct Frame *frame, struct Packet *packet); 82 | 83 | 84 | /* How the DNS server receives DNS request packets */ 85 | void 86 | network_receive(struct Frame *frame, 87 | struct Thread *thread, 88 | struct Adapter *adapter, 89 | unsigned secs, 90 | unsigned usecs, 91 | const unsigned char *px, 92 | unsigned length); 93 | 94 | 95 | void proto_ethernet_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max); 96 | void proto_ip_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max); 97 | 98 | void proto_arp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max); 99 | void proto_arp_process(struct Frame *frame, const struct ARP_IncomingRequest *arp); 100 | 101 | void proto_icmp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max); 102 | void proto_icmp_process(struct Frame *frame, const struct ICMP_IncomingRequest *icmp); 103 | 104 | void proto_udp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max); 105 | 106 | void proto_dns_process(const struct DNS_Incoming *dns, 107 | const struct Catalog *catalog, 108 | struct Packet *pkt); 109 | 110 | 111 | void stack_send_ip(struct Frame *frame, const unsigned char px[], unsigned length, unsigned ip_dst); 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | #endif 117 | -------------------------------------------------------------------------------- /src/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKET_H 2 | #define PACKET_H 3 | 4 | struct Packet 5 | { 6 | unsigned char *buf; 7 | unsigned offset; 8 | unsigned max; 9 | struct { 10 | unsigned network; 11 | unsigned transport; 12 | } fixup; 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/pixie-atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef PIXIE_ATOMIC_H 2 | #define PIXIE_ATOMIC_H 3 | 4 | #if defined(_MSC_VER) 5 | #include 6 | #define __sync_fetch_and_add(p,n) _InterlockedExchangeAdd(p, n) 7 | #define __sync_fetch_and_sub(p,n) _InterlockedExchangeAdd(p, -(n)) 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/pixie-nic.h: -------------------------------------------------------------------------------- 1 | #ifndef PIXIE_NIC_H 2 | #define PIXIE_NIC_H 3 | #include 4 | 5 | /** 6 | * Tests to see if the named network adapter exists 7 | * 8 | * @param ifname 9 | * The name of a network interface 10 | * @return 11 | * 1 if the named network interface exists 12 | * 0 if it doesn't exists or is somehow invalid 13 | */ 14 | unsigned pixie_nic_exists(const char *ifname); 15 | 16 | unsigned pixie_nic_get_default(char *ifname, size_t ifname_size); 17 | 18 | unsigned pixie_nic_get_ipv4(const char *ifname); 19 | 20 | unsigned pixie_nic_get_mac(const char *ifname, unsigned char *mac); 21 | 22 | unsigned pixie_nic_gateway(const char *ifname, unsigned *ipv4); 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/pixie-sockets.h: -------------------------------------------------------------------------------- 1 | #ifndef PIXIE_SOCKETS_H 2 | #define PIXIE_SOCKETS_H 3 | #if defined(_MSC_VER) 4 | #pragma warning(disable:6386) 5 | #endif 6 | 7 | #if defined(WIN32) 8 | #include 9 | #include 10 | #define WSA(err) WSA##err 11 | #if defined(_MSC_VER) 12 | #pragma comment(lib, "ws2_32.lib") 13 | #pragma warning(disable:4389) 14 | #pragma warning(disable:4127) 15 | #endif 16 | typedef int socklen_t; 17 | #else 18 | #include 19 | #include 20 | #include 21 | #define WSAGetLastError() (errno) 22 | #define SOCKET int 23 | #define WSA(err) (err) 24 | #define closesocket(fd) close(fd) 25 | #endif 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/pixie-threads.h: -------------------------------------------------------------------------------- 1 | #ifndef PORT_THREADS_H 2 | #define PORT_THREADS_H 3 | #include 4 | #include 5 | #if defined(_MSC_VER) 6 | #include 7 | #endif 8 | 9 | /** 10 | * Returns the number of CPUs in the system, including virtual CPUs. 11 | * On a single processor system, the number returned will be '1'. 12 | * On a dual socket, dual-core per socket, hyperthreaded system, the 13 | * count will be '8'. 14 | */ 15 | unsigned pixie_cpu_get_count(void); 16 | 17 | /** 18 | * Launch a thread 19 | */ 20 | size_t 21 | pixie_begin_thread(void (*worker_thread)(void*), 22 | unsigned flags, 23 | void *worker_data); 24 | 25 | void pixie_cpu_set_affinity(unsigned processor); 26 | void pixie_cpu_raise_priority(void); 27 | 28 | //void pixie_locked_subtract_u32(unsigned *lhs, unsigned rhs); 29 | 30 | void 31 | pixie_join(size_t thread_handle, size_t *exit_code); 32 | 33 | 34 | 35 | #if defined(_MSC_VER) 36 | #define pixie_locked_add_u32(dst, src) _InterlockedExchangeAdd((volatile long*)(dst), (src)) 37 | #define pixie_locked_CAS32(dst, src, expected) (_InterlockedCompareExchange((volatile long*)dst, src, expected) == (expected)) 38 | #define pixie_locked_CAS64(dst, src, expected) (_InterlockedCompareExchange64((volatile long long*)dst, src, expected) == (expected)) 39 | #define rte_atomic32_cmpset(dst, exp, src) (_InterlockedCompareExchange((volatile long *)dst, (long)src, (long)exp)==(long)(exp)) 40 | 41 | #elif defined(__GNUC__) 42 | #define pixie_locked_add_u32(dst, src) __sync_add_and_fetch((volatile int*)(dst), (int)(src)); 43 | #define rte_atomic32_cmpset(dst, expected, src) __sync_bool_compare_and_swap((volatile int*)(dst),(int)expected,(int)src) 44 | #define pixie_locked_CAS32(dst, src, expected) __sync_bool_compare_and_swap((volatile int*)(dst),(int)expected,(int)src) 45 | #define pixie_locked_CAS64(dst, src, expected) __sync_bool_compare_and_swap((volatile long long int*)(dst),(long long int)expected,(long long int)src) 46 | 47 | #if defined(__arm__) 48 | #define rte_wmb() __sync_synchronize() 49 | #define rte_rmb() __sync_synchronize() 50 | #define rte_pause() 51 | #else 52 | #define rte_wmb() asm volatile("sfence;" : : : "memory") 53 | #define rte_rmb() asm volatile("lfence;" : : : "memory") 54 | #define rte_pause() asm volatile ("pause") 55 | #endif 56 | #else 57 | unsigned pixie_locked_add_u32(volatile unsigned *lhs, unsigned rhs); 58 | int pixie_locked_CAS32(volatile unsigned *dst, unsigned src, unsigned expected); 59 | int pixie_locked_CAS64(volatile uint64_t *dst, uint64_t src, uint64_t expected); 60 | #endif 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/pixie-timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | portability: time 3 | 4 | Since this program runs on both Linux and Windows, I need a portable 5 | way to get a high-resolution timer. 6 | 7 | NOTE: The time I'm looking for is "elapsed time" not "wall clock" 8 | time. In other words, if you put the system to sleep and wake it 9 | up a day later, this function should see no change, since time 10 | wasn't elapsing while the system was asleep. 11 | 12 | Reference: 13 | http://www.python.org/dev/peps/pep-0418/#monotonic-clocks 14 | http://www.brain-dump.org/blog/entry/107 15 | 16 | */ 17 | #include "pixie-timer.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | #if defined(WIN32) 26 | #include 27 | 28 | LARGE_INTEGER 29 | getFILETIMEoffset(void) 30 | { 31 | SYSTEMTIME s; 32 | FILETIME f; 33 | LARGE_INTEGER t; 34 | 35 | s.wYear = 1970; 36 | s.wMonth = 1; 37 | s.wDay = 1; 38 | s.wHour = 0; 39 | s.wMinute = 0; 40 | s.wSecond = 0; 41 | s.wMilliseconds = 0; 42 | SystemTimeToFileTime(&s, &f); 43 | t.QuadPart = f.dwHighDateTime; 44 | t.QuadPart <<= 32; 45 | t.QuadPart |= f.dwLowDateTime; 46 | return (t); 47 | } 48 | 49 | int 50 | clock_gettime(int X, struct timeval *tv) 51 | { 52 | LARGE_INTEGER t; 53 | FILETIME f; 54 | double microseconds; 55 | static LARGE_INTEGER offset; 56 | static double frequencyToMicroseconds; 57 | static int initialized = 0; 58 | static BOOL usePerformanceCounter = 0; 59 | 60 | X=X; 61 | 62 | if (!initialized) { 63 | LARGE_INTEGER performanceFrequency; 64 | initialized = 1; 65 | usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); 66 | if (usePerformanceCounter) { 67 | QueryPerformanceCounter(&offset); 68 | frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; 69 | } else { 70 | offset = getFILETIMEoffset(); 71 | frequencyToMicroseconds = 10.; 72 | } 73 | } 74 | if (usePerformanceCounter) QueryPerformanceCounter(&t); 75 | else { 76 | GetSystemTimeAsFileTime(&f); 77 | t.QuadPart = f.dwHighDateTime; 78 | t.QuadPart <<= 32; 79 | t.QuadPart |= f.dwLowDateTime; 80 | } 81 | 82 | t.QuadPart -= offset.QuadPart; 83 | microseconds = (double)t.QuadPart / frequencyToMicroseconds; 84 | t.QuadPart = (LONGLONG)microseconds; 85 | tv->tv_sec = (long)(t.QuadPart / 1000000); 86 | tv->tv_usec = t.QuadPart % 1000000; 87 | return (0); 88 | } 89 | 90 | 91 | uint64_t 92 | pixie_gettime(void) 93 | { 94 | //struct timeval tv; 95 | //clock_gettime(0, &tv); 96 | 97 | uint64_t time1 = 0, freq = 0; 98 | double seconds; 99 | 100 | QueryPerformanceCounter((LARGE_INTEGER *) &time1); 101 | QueryPerformanceFrequency((LARGE_INTEGER *)&freq); 102 | 103 | seconds = (double)time1/(double)freq; 104 | 105 | return (uint64_t)(seconds * 1000000.0); 106 | 107 | //return (uint64_t)tv.tv_sec * 1000000UL + tv.tv_usec; 108 | } 109 | uint64_t 110 | pixie_nanotime(void) 111 | { 112 | uint64_t time1 = 0, freq = 0; 113 | double seconds; 114 | QueryPerformanceCounter((LARGE_INTEGER *) &time1); 115 | QueryPerformanceFrequency((LARGE_INTEGER *)&freq); 116 | seconds = (double)time1/(double)freq; 117 | return (uint64_t)(seconds * 1000000000.0); 118 | } 119 | 120 | void 121 | pixie_mssleep(unsigned waitTime) 122 | { 123 | Sleep(waitTime); 124 | } 125 | 126 | void 127 | pixie_usleep(uint64_t waitTime) 128 | { 129 | /* 130 | uint64_t time1 = 0, time2 = 0, freq = 0; 131 | 132 | QueryPerformanceCounter((LARGE_INTEGER *) &time1); 133 | QueryPerformanceFrequency((LARGE_INTEGER *)&freq); 134 | 135 | do { 136 | QueryPerformanceCounter((LARGE_INTEGER *) &time2); 137 | } while((time2-time1) < waitTime); 138 | */ 139 | 140 | uint64_t start; 141 | 142 | start = pixie_gettime(); 143 | 144 | if (waitTime > 1000) 145 | Sleep((DWORD)(waitTime/1000)); 146 | 147 | while (pixie_gettime() - start < waitTime) 148 | ; 149 | } 150 | #elif defined(CLOCK_MONOTONIC) 151 | #include 152 | 153 | void 154 | pixie_mssleep(unsigned milliseconds) 155 | { 156 | pixie_usleep(milliseconds * 1000ULL); 157 | } 158 | 159 | void 160 | pixie_usleep(uint64_t microseconds) 161 | { 162 | struct timespec ts; 163 | struct timespec remaining; 164 | int err; 165 | 166 | ts.tv_sec = microseconds/1000000; 167 | ts.tv_nsec = (microseconds%1000000) * 1000; 168 | 169 | again: 170 | err = nanosleep(&ts, &remaining); 171 | if (err == -1 && errno == EINTR) { 172 | memcpy(&ts, &remaining, sizeof(ts)); 173 | goto again; 174 | } 175 | 176 | //usleep(microseconds); 177 | } 178 | uint64_t 179 | pixie_gettime(void) 180 | { 181 | int x; 182 | struct timespec tv; 183 | 184 | #ifdef CLOCK_MONOTONIC_RAW 185 | x = clock_gettime(CLOCK_MONOTONIC_RAW, &tv); 186 | #else 187 | x = clock_gettime(CLOCK_MONOTONIC, &tv); 188 | #endif 189 | if (x != 0) { 190 | printf("clock_gettime() err %d\n", errno); 191 | } 192 | 193 | return tv.tv_sec * 1000000 + tv.tv_nsec/1000; 194 | } 195 | uint64_t 196 | pixie_nanotime(void) 197 | { 198 | int x; 199 | struct timespec tv; 200 | 201 | #ifdef CLOCK_MONOTONIC_RAW 202 | x = clock_gettime(CLOCK_MONOTONIC_RAW, &tv); 203 | #else 204 | x = clock_gettime(CLOCK_MONOTONIC, &tv); 205 | #endif 206 | if (x != 0) { 207 | printf("clock_gettime() err %d\n", errno); 208 | } 209 | 210 | return tv.tv_sec * 1000000000 + tv.tv_nsec; 211 | } 212 | #elif defined(__MACH__) || defined(__FreeBSD__) /* works for Apple */ 213 | #include 214 | #include 215 | 216 | void pixie_usleep(uint64_t microseconds) 217 | { 218 | struct timespec t; 219 | t.tv_nsec = microseconds * 1000; 220 | if (microseconds > 1000000) 221 | t.tv_sec = microseconds/1000000; 222 | else { 223 | t.tv_sec = 0; 224 | } 225 | 226 | nanosleep(&t, 0); 227 | //usleep(microseconds); 228 | } 229 | void 230 | pixie_mssleep(unsigned milliseconds) 231 | { 232 | pixie_usleep(milliseconds * 1000ULL); 233 | } 234 | uint64_t 235 | pixie_gettime(void) 236 | { 237 | return mach_absolute_time()/1000; 238 | } 239 | uint64_t 240 | pixie_nanotime(void) 241 | { 242 | return mach_absolute_time(); 243 | } 244 | #endif 245 | 246 | int pixie_time_selftest(void) 247 | { 248 | static const uint64_t duration = 123456; 249 | uint64_t start, stop, elapsed; 250 | 251 | 252 | start = pixie_gettime(); 253 | pixie_usleep(duration); 254 | stop = pixie_gettime(); 255 | elapsed = stop - start; 256 | 257 | if (elapsed < 0.9*duration || 1.1*duration < elapsed) { 258 | /* I wonder how often this will fail just because the process 259 | * gets swapped out, but I'm leaving it in to see if people notice */ 260 | fprintf(stderr, "timing error, long delay\n"); 261 | return 1; 262 | } 263 | 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /src/pixie-timer.h: -------------------------------------------------------------------------------- 1 | #ifndef PIXIE_TIMER_H 2 | #define PIXIE_TIMER_H 3 | #include 4 | 5 | /** 6 | * The current time, in microseconds 7 | */ 8 | uint64_t pixie_gettime(void); 9 | 10 | /** 11 | * The current time, in nanoseconds 12 | */ 13 | uint64_t pixie_nanotime(void); 14 | 15 | /** 16 | * Wait the specified number of microseconds 17 | */ 18 | void pixie_usleep(uint64_t usec); 19 | 20 | /** 21 | * Wait the specified number of milliseconds 22 | */ 23 | void pixie_mssleep(unsigned milliseconds); 24 | 25 | /** 26 | * Do a self-test. Note that in some cases, this may 27 | * actaully fail when there is no problem. So far it hasn't, but I should 28 | * probably add some code to fix this. 29 | */ 30 | int pixie_time_selftest(void); 31 | 32 | 33 | 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/pixie.h: -------------------------------------------------------------------------------- 1 | /* Copyright: (c) 2009-2010 by Robert David Graham 2 | ** License: This code is private to the author, and you do not 3 | ** have a license to run it, or own a copy, unless given 4 | ** a license personally by the author. This is 5 | ** explained in the LICENSE file at the root of the project. 6 | **/ 7 | #ifndef PIXIE_H 8 | #define PIXIE_H 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #include 14 | #include 15 | #define bool int 16 | 17 | #if WIN32 18 | #include 19 | #define getcwd _getcwd 20 | #else 21 | #include 22 | #endif 23 | 24 | 25 | typedef void (*PIXIE_FUNCTION)(void); 26 | 27 | void *pixie_opendir(const char *name); 28 | int pixie_closedir(void *v_dir); 29 | const char *pixie_readdir(void *dir); 30 | 31 | uint64_t pixie_get_filesize(const char *filename); 32 | 33 | /* WIN32: FormatMessage(GetLastError) 34 | * LINUX: strerror(errno)*/ 35 | void pixie_strerror(char *error_msg, size_t sizeof_error_msg); 36 | 37 | /* WIN32: LoadLibrary() 38 | * LINUX: dlopen() */ 39 | void *pixie_load_library(const char *library_name); 40 | void pixie_close_library(void *library_handle); 41 | 42 | /* WIN32: GetProcAddress() 43 | * LINUX: dlsym() */ 44 | PIXIE_FUNCTION pixie_get_proc_symbol(void *library, const char *symbol); 45 | 46 | void pixie_sleep(unsigned milliseconds); 47 | 48 | #if 0 49 | void pixie_close_thread(ptrdiff_t thread_handle); 50 | void pixie_end_thread(void); 51 | 52 | void *pixie_initialize_critical_section(); 53 | void pixie_delete_critical_section(void *cs); 54 | void pixie_leave_critical_section(void *cs); 55 | void pixie_enter_critical_section(void *cs); 56 | void pixie_lower_thread_priority(void); 57 | void pixie_raise_thread_priority(void); 58 | uint64_t pixie_microseconds(void); 59 | 60 | void pixie_cpu_set_affinity(unsigned processor); 61 | #endif 62 | 63 | /** 64 | * Get the number CPUs in the system. This does not get CPU geomtry, 65 | * so there is no way to discover the number of sockets, or hypterthreads. 66 | * A quad-core hyper-threaded Nehalem CPU will return a count of "8". 67 | */ 68 | unsigned pixie_cpu_get_count(); 69 | 70 | /** 71 | * Retrieve the 6-byte MAC address of the local computer. This is 72 | * complicated by the fact that there is no robust API on systems to 73 | * get this address. The reason there is no simple method is that 74 | * computers may not have a network card at all, and thus no MAC address. 75 | * For example, a computer that connects via Bluetooth or dialup will 76 | * not have a MAC address. Another complication is that a computer may have 77 | * more than one network card, such as an Ethernet card and a WiFi card. 78 | */ 79 | unsigned pixie_get_mac_address(unsigned char macaddr[6]); 80 | 81 | /** 82 | * WIN32: GetComputerName() 83 | * LINUX: get_host_name() 84 | */ 85 | unsigned pixie_get_host_name(char *name, unsigned name_size); 86 | 87 | //unsigned pixie_locked_xadd_u32(unsigned *lhs, unsigned rhs); 88 | 89 | //void pixie_locked_add_u32(volatile unsigned *lhs, unsigned rhs); 90 | //void pixie_locked_subtract_u32(unsigned *lhs, unsigned rhs); 91 | //bool pixie_locked_CAS32(volatile unsigned *dst, unsigned src, unsigned expected); 92 | //bool pixie_locked_CAS64(volatile uint64_t *dst, uint64_t src, uint64_t expected); 93 | //bool pixie_locked_CAS128(volatile void *dst, unsigned src, unsigned expected); 94 | 95 | #if defined(_MSC_VER) 96 | #include 97 | #elif defined(__GNUC__) 98 | static __inline__ unsigned long long __rdtsc(void) 99 | { 100 | unsigned long hi = 0, lo = 0; 101 | __asm__ __volatile__ ("lfence\n\trdtsc" : "=a"(lo), "=d"(hi)); 102 | return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 103 | } 104 | #endif 105 | 106 | void 107 | pixie_get_memory_size(uint64_t *available, uint64_t *total_physical); 108 | 109 | 110 | /** 111 | * Configure the thread to ignore all signals sent to it. This assumes 112 | * that the main thread is handling signals, or that you've started a 113 | * special signals-only thread. 114 | */ 115 | //void pixie_thread_ignore_signals(); 116 | 117 | 118 | /** 119 | * Thread "barriers" 120 | */ 121 | /*#if defined(WIN32) 122 | typedef struct pixie_barrier_t { 123 | int count; 124 | int total; 125 | void *cs; 126 | void *cv; 127 | } pixie_barrier_t; 128 | #define PIXIE_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0} 129 | #define PIXIE_BARRIER_INITIALIZER {0,0,PIXIE_MUTEX_INITIALIZER,{0}} 130 | #define PIXIE_BARRIER_SERIAL_THREAD 1 131 | #elif defined(__GNUC__) 132 | #define pixie_barrier_t pthread_barrier_t 133 | #endif 134 | */ 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | #endif 140 | -------------------------------------------------------------------------------- /src/proto-arp.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "adapter.h" 3 | 4 | #define VERIFY_REMAINING(n) if (offset+(n) > max) return; 5 | 6 | /**************************************************************************** 7 | ****************************************************************************/ 8 | void 9 | proto_arp_process(struct Frame *frame, const struct ARP_IncomingRequest *arp) 10 | { 11 | struct Packet pkt; 12 | unsigned char *px; 13 | unsigned offset; 14 | 15 | if (!arp->is_valid) 16 | return; 17 | 18 | switch (arp->opcode) { 19 | case 1: /* request */ 20 | /* Ignore ARP packets that aren't sent to our IP address */ 21 | if (!adapter_has_ipv4(frame->adapter, arp->ip_dst)) 22 | return; 23 | 24 | /* 25 | * Create a response packet that will be sent back to the sender 26 | * of this packet 27 | */ 28 | pkt = frame_create_response(frame, NET_ETHERNET); 29 | px = pkt.buf; 30 | offset = pkt.offset; 31 | 32 | /* 33 | * Format outgoing Ethernet header 34 | */ 35 | memcpy(&px[offset + 0], arp->mac_dst, 6); /* Ethernet destination */ 36 | memcpy(&px[offset + 6], frame->adapter->mac[0].address, 6); /* Ethernet source */ 37 | memcpy(&px[offset + 12], "\x08\x06", 2); /* Ethertype */ 38 | 39 | /* 40 | * Format ARP header 41 | */ 42 | px[offset++] = (unsigned char)(arp->hardware_type>>8); 43 | px[offset++] = (unsigned char)(arp->hardware_type>>0); 44 | px[offset++] = (unsigned char)(arp->protocol_type>>8); 45 | px[offset++] = (unsigned char)(arp->protocol_type>>0); 46 | px[offset++] = (unsigned char)(arp->hardware_length); 47 | px[offset++] = (unsigned char)(arp->protocol_length); 48 | px[offset++] = (unsigned char)(0); 49 | px[offset++] = (unsigned char)(2); /* reply */ 50 | 51 | /* Set our source address */ 52 | memcpy(&px[offset], frame->adapter->mac[0].address, 6); 53 | offset += 6; 54 | px[offset++] = (unsigned char)(arp->ip_dst>>24); 55 | px[offset++] = (unsigned char)(arp->ip_dst>>16); 56 | px[offset++] = (unsigned char)(arp->ip_dst>> 8); 57 | px[offset++] = (unsigned char)(arp->ip_dst>> 0); 58 | 59 | /* Set our destination address */ 60 | memcpy(&px[offset], arp->mac_src, 6); 61 | offset += 6; 62 | px[offset++] = (unsigned char)(arp->ip_src>>24); 63 | px[offset++] = (unsigned char)(arp->ip_src>>16); 64 | px[offset++] = (unsigned char)(arp->ip_src>> 8); 65 | px[offset++] = (unsigned char)(arp->ip_src>> 0); 66 | 67 | /* 68 | * Send the packet 69 | */ 70 | pkt.offset = offset; 71 | pkt.max = offset; 72 | break; 73 | case 2: /* reply */ 74 | pkt.offset = pkt.max = 0; 75 | break; 76 | default: 77 | /* we don't handle any other ARPs */ 78 | pkt.offset = pkt.max = 0; 79 | break; 80 | } 81 | 82 | /* 83 | * Now transmit the packet 84 | */ 85 | frame_xmit_response(frame, &pkt); 86 | } 87 | 88 | 89 | /**************************************************************************** 90 | ****************************************************************************/ 91 | void 92 | proto_arp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max) 93 | { 94 | struct ARP_IncomingRequest *arp = frame->arp; 95 | 96 | /* 97 | * parse the header 98 | */ 99 | VERIFY_REMAINING(8); 100 | frame->net_protocol = NET_ARP; 101 | arp->is_valid = 0; /* not valid yet */ 102 | 103 | arp->hardware_type = px[offset]<<8 | px[offset+1]; 104 | arp->protocol_type = px[offset+2]<<8 | px[offset+3]; 105 | arp->hardware_length = px[offset+4]; 106 | arp->protocol_length = px[offset+5]; 107 | arp->opcode = px[offset+6]<<8 | px[offset+7]; 108 | offset += 8; 109 | 110 | /* We only support IPv4 and Ethernet addresses */ 111 | if (arp->protocol_length != 4 && arp->hardware_length != 6) 112 | return; 113 | if (arp->protocol_type != 0x0800) 114 | return; 115 | if (arp->hardware_type != 1 && arp->hardware_type != 6) 116 | return; 117 | 118 | /* 119 | * parse the addresses 120 | */ 121 | VERIFY_REMAINING(2 * arp->hardware_length + 2 * arp->protocol_length); 122 | arp->mac_src = px+offset; 123 | offset += arp->hardware_length; 124 | 125 | arp->ip_src = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3]; 126 | offset += arp->protocol_length; 127 | 128 | arp->mac_dst = px+offset; 129 | offset += arp->hardware_length; 130 | 131 | arp->ip_dst = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3]; 132 | offset += arp->protocol_length; 133 | 134 | arp->is_valid = 1; 135 | 136 | frame->ip_dst = arp->ip_dst; 137 | frame->ip_src = arp->ip_src; 138 | } 139 | -------------------------------------------------------------------------------- /src/proto-dns-compressor.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTO_DNS_COMPRESSOR_H 2 | #define PROTO_DNS_COMPRESSOR_H 3 | struct DNS_OutgoingResponse; 4 | struct Packet; 5 | struct DomainPointer; 6 | 7 | /**************************************************************************** 8 | ****************************************************************************/ 9 | struct CompressorId { 10 | const unsigned char *label; 11 | unsigned short sibling; 12 | unsigned short child; 13 | unsigned short compression_code; 14 | }; 15 | struct Compressor 16 | { 17 | unsigned offset_start; 18 | unsigned count; 19 | struct CompressorId ids[1000]; 20 | }; 21 | 22 | void compressor_init(struct Compressor *compressor, const struct DNS_OutgoingResponse *response, unsigned offset_start); 23 | void compressor_append_name(struct Compressor *compressor, struct Packet *pkt, struct DomainPointer name, struct DomainPointer origin); 24 | int compressor_selftest(const struct DNS_OutgoingResponse *response); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/proto-dns-formatter.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTO_DNS_FORMATTER_H 2 | #define PROTO_DNS_FORMATTER_H 3 | #include "domainname.h" 4 | struct Packet; 5 | 6 | struct DNS_ResponseRRset 7 | { 8 | struct DomainPointer name; 9 | struct DomainPointer origin; 10 | const struct DBrrset *rrset; 11 | }; 12 | 13 | struct DNS_OutgoingResponse 14 | { 15 | unsigned id; 16 | unsigned is_version_bind:1; 17 | unsigned aa:1; 18 | unsigned ra:1; 19 | unsigned tc:1; 20 | unsigned rcode; 21 | unsigned opcode; 22 | 23 | unsigned ancount; 24 | unsigned nscount; 25 | unsigned arcount; 26 | 27 | int query_type; 28 | struct DomainPointer query_name; 29 | 30 | struct DNS_ResponseRRset rrsets[4096]; 31 | }; 32 | 33 | enum { 34 | RCODE_OK = 0, 35 | RCODE_FORMERR = 1, 36 | RCODE_NXDOMAIN = 3, 37 | RCODE_REFUSED = 5, 38 | }; 39 | 40 | 41 | 42 | enum { 43 | SECTION_ANSWER=1, 44 | SECTION_AUTHORITATIVE, 45 | SECTION_ADDITIONAL, 46 | }; 47 | 48 | /** 49 | * Convert the internal representation of a response into the external 50 | * form, formatting a DNS response packet 51 | */ 52 | void dns_format_response(struct DNS_OutgoingResponse *response, 53 | struct Packet *pkt); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/proto-dns.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTO_DNS_H 2 | #define PROTO_DNS_H 3 | #include "domainname.h" 4 | 5 | struct DNS_Incoming 6 | { 7 | unsigned id; /* transaction id */ 8 | unsigned is_valid:1; 9 | unsigned is_formerr:1; 10 | unsigned is_edns0:1;/* edns0 features found */ 11 | unsigned qr:1; /* 'query' or 'response' */ 12 | unsigned aa:1; /* 'authoritative answer' */ 13 | unsigned tc:1; /* 'truncation' */ 14 | unsigned rd:1; /* 'recursion desired' */ 15 | unsigned ra:1; /* 'recursion available' */ 16 | unsigned z:3; /* reserved */ 17 | unsigned opcode; 18 | unsigned rcode; /* response error code */ 19 | unsigned qdcount; /* query count */ 20 | unsigned ancount; /* answer count */ 21 | unsigned nscount; /* name-server/authority count */ 22 | unsigned arcount; /* additional record count */ 23 | struct { 24 | unsigned payload_size; 25 | unsigned version; 26 | unsigned z; 27 | } edns0; 28 | const unsigned char *req; 29 | unsigned req_length; 30 | 31 | /* the query name */ 32 | struct DomainPointer query_name; 33 | unsigned query_type; 34 | unsigned query_class; 35 | unsigned char query_name_buffer[256]; 36 | 37 | unsigned rr_count; 38 | unsigned short rr_offset[1024]; 39 | unsigned edns0_offset; 40 | }; 41 | 42 | void proto_dns_parse(struct DNS_Incoming *dns, const unsigned char px[], unsigned offset, unsigned max); 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/proto-icmp.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "thread.h" 3 | 4 | #define VERIFY_REMAINING(n) if (offset+(n) > max) return; 5 | 6 | 7 | /**************************************************************************** 8 | ****************************************************************************/ 9 | void 10 | proto_icmp_process(struct Frame *frame, const struct ICMP_IncomingRequest *icmp) 11 | { 12 | unsigned char *px; 13 | unsigned offset; 14 | struct Packet pkt; 15 | unsigned checksum; 16 | 17 | /* 18 | * We only handle ICMP ping requests 19 | */ 20 | if (icmp->type != 8) { 21 | frame->thread->stats.icmp_bad_type++; 22 | return; 23 | } 24 | 25 | /* 26 | * Only handle short, unfragmented pings 27 | */ 28 | if (icmp->payload_length > 1400) 29 | return; 30 | 31 | /* 32 | * Grab a transmit buffer 33 | */ 34 | pkt = frame_create_response(frame, NET_IP); 35 | px = pkt.buf; 36 | offset = pkt.offset; 37 | 38 | /* 39 | * The new checksum is just a conversion o the old checksum 40 | */ 41 | checksum = ~(icmp->original_checksum); 42 | checksum -= 0x800; 43 | checksum = (checksum&0xFFFF) + (checksum>>16); 44 | checksum = (checksum&0xFFFF) + (checksum>>16); 45 | checksum = ~checksum; 46 | 47 | /* 48 | * create echo response 49 | */ 50 | offset = 0; 51 | px[offset++] = 0; 52 | px[offset++] = 0; 53 | px[offset++] = (unsigned char)(checksum>>8); 54 | px[offset++] = (unsigned char)(checksum>>0); 55 | 56 | /* 57 | * Echo the contents exacty 58 | */ 59 | if (offset + icmp->payload_length <= pkt.max) 60 | memcpy(&px[offset], icmp->payload, icmp->payload_length); 61 | offset += icmp->payload_length; 62 | 63 | 64 | pkt.offset = offset; 65 | pkt.max = pkt.offset; 66 | frame_xmit_response(frame, &pkt); 67 | } 68 | 69 | /**************************************************************************** 70 | ****************************************************************************/ 71 | void 72 | proto_icmp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max) 73 | { 74 | struct ICMP_IncomingRequest *icmp = frame->icmp; 75 | unsigned i; 76 | unsigned checksum_length; 77 | unsigned checksum; 78 | 79 | 80 | VERIFY_REMAINING(4); 81 | frame->net_protocol = NET_ICMP; 82 | 83 | icmp->type = px[offset+0]; 84 | icmp->code = px[offset+1]; 85 | icmp->original_checksum = px[offset+2]<<8 | px[offset+3]; 86 | icmp->payload_length = max - offset - 4; 87 | icmp->payload = px+4; 88 | 89 | /* 90 | * Validate checksum 91 | */ 92 | checksum = 0; 93 | checksum_length = (max-offset) & (~1); 94 | for (i=0; i>16); 100 | checksum = (checksum&0xFFFF) + (checksum>>16); 101 | icmp->is_checksum_checked = 1; 102 | if (checksum != 0xffff) { 103 | frame->thread->stats.icmp_bad_checksum++; 104 | icmp->is_checksum_valid = 0; 105 | //return; 106 | } 107 | icmp->is_checksum_valid = 1; 108 | 109 | icmp->is_valid = 1; 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/proto-ip.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "thread.h" 3 | #include "adapter.h" 4 | #include 5 | 6 | #define VERIFY_REMAINING(n) if (offset+(n) > max) return; 7 | 8 | /**************************************************************************** 9 | * parse the IPv4 header 10 | ****************************************************************************/ 11 | void 12 | proto_ip_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max) 13 | { 14 | unsigned checksum = 0; 15 | unsigned i; 16 | struct { 17 | unsigned header_length; 18 | unsigned total_length; 19 | unsigned id; 20 | unsigned flags; 21 | unsigned ttl; 22 | unsigned protocol; 23 | unsigned src; 24 | unsigned dst; 25 | } ip; 26 | 27 | frame->net_protocol = NET_IP; 28 | VERIFY_REMAINING(1); 29 | 30 | /* Must be IPv4 */ 31 | if ((px[offset+0]>>4) != 4) 32 | return; 33 | 34 | /* Must be at least 20 bytes */ 35 | if ((px[offset+0]&0xF) < 5) 36 | return; 37 | 38 | /* Make sure we have a full header */ 39 | ip.header_length = (px[offset] & 0x0F) * 4; 40 | VERIFY_REMAINING(ip.header_length); 41 | 42 | /* Verify the checksum */ 43 | checksum = 0; 44 | for (i=0; i>16); 48 | frame->ip_checksum_is_valid = (checksum == 0xFFFF); 49 | 50 | 51 | /* 52 | * Decode the header 53 | */ 54 | ip.total_length = px[offset+2]<<8 | px[offset+3]; 55 | ip.id = px[offset+4]<<8 | px[offset+5]; 56 | ip.flags =px[offset+6] & 0x0f; 57 | ip.ttl = px[offset+8]; 58 | ip.protocol = px[offset+9]; 59 | frame->ip_ver = 4; 60 | frame->ip_src = px[offset+12]<<24 | px[offset+13]<<16 | px[offset+14]<<8 | px[offset+15]; 61 | frame->ip_dst = px[offset+16]<<24 | px[offset+17]<<16 | px[offset+18]<<8 | px[offset+19]; 62 | offset += 20; 63 | 64 | /* Process IP options */ 65 | /* TODO: right now we ignore all IP options. Should support some 66 | * of them I suppose */ 67 | offset += ip.header_length - 20; 68 | 69 | 70 | switch (ip.protocol) { 71 | case 1: /* ICMP */ 72 | proto_icmp_parse(frame, px, offset, max); 73 | break; 74 | case 6: /* TCP */ 75 | break; 76 | case 17: /* UDP */ 77 | proto_udp_parse(frame, px, offset, max); 78 | break; 79 | } 80 | 81 | return; 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/proto-preprocess.h: -------------------------------------------------------------------------------- 1 | /* Copyright: (c) 2009-2010 by Robert David Graham 2 | ** License: This code is private to the author, and you do not 3 | ** have a license to run it, or own a copy, unless given 4 | ** a license personally by the author. This is 5 | ** explained in the LICENSE file at the root of the project. 6 | **/ 7 | #ifndef PREPROCESS_H 8 | #define PREPROCESS_H 9 | 10 | enum { 11 | FOUND_NOTHING=0, 12 | FOUND_ETHERNET, 13 | FOUND_IPV4, 14 | FOUND_IPV6, 15 | FOUND_ICMP, 16 | FOUND_TCP, 17 | FOUND_UDP, 18 | FOUND_DNS, 19 | FOUND_IPV6_HOP, 20 | FOUND_8021Q, 21 | FOUND_MPLS, 22 | FOUND_WIFI_DATA, 23 | FOUND_WIFI, 24 | FOUND_RADIOTAP, 25 | FOUND_PRISM, 26 | FOUND_LLC, 27 | FOUND_ARP, 28 | }; 29 | struct PreprocessedInfo { 30 | const unsigned char *mac_src; 31 | const unsigned char *mac_dst; 32 | const unsigned char *mac_bss; 33 | unsigned ip_offset; /* 14 for normal Ethernet */ 34 | unsigned ip_version; /* 4 or 6 */ 35 | unsigned ip_protocol; /* 6 for TCP, 11 for UDP */ 36 | const unsigned char *ip_src; 37 | const unsigned char *ip_dst; 38 | unsigned transport_offset; /* 34 for normal Ethernet */ 39 | unsigned port_src; 40 | unsigned port_dst; 41 | 42 | int found; 43 | int found_offset; 44 | }; 45 | 46 | unsigned 47 | preprocess_frame(const unsigned char *px, unsigned length, unsigned link_type, struct PreprocessedInfo *info); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/proto-udp.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | 3 | #define VERIFY_REMAINING(n) if (offset+(n) > max) return; 4 | 5 | /**************************************************************************** 6 | * 'parse' incoming UDP packets. We do little more than record 7 | * the port numbers and pass execution onto the next layer. 8 | ****************************************************************************/ 9 | void 10 | proto_udp_parse(struct Frame *frame, const unsigned char px[], unsigned offset, unsigned max) 11 | { 12 | unsigned checksum; 13 | unsigned udp_length; 14 | 15 | frame->net_protocol = NET_UDP; 16 | 17 | VERIFY_REMAINING(8); 18 | frame->port_src = px[offset+0]<<8 | px[offset+1]; 19 | frame->port_dst = px[offset+2]<<8 | px[offset+3]; 20 | 21 | /* 22 | * 'length' field 23 | */ 24 | udp_length = px[offset+4]<<8 | px[offset+5]; 25 | if (udp_length < 8) { 26 | return; 27 | } else if (udp_length > max) { 28 | return; 29 | } 30 | max = offset + udp_length; /* shrink remaining length to fit UDP length */ 31 | 32 | /* 33 | * 'checksum' field. 34 | * TODO: skip this step when the underlying adapter offloads 35 | * checksumming, which is most adapters these days. 36 | */ 37 | checksum = px[offset+6]<<8 | px[offset+7]; 38 | if (checksum) { 39 | unsigned i; 40 | 41 | checksum = (frame->ip_src>>16)&0xFFFF; 42 | checksum += (frame->ip_src>> 0)&0xFFFF; 43 | checksum += (frame->ip_dst>>16)&0xFFFF; 44 | checksum += (frame->ip_dst>> 0)&0xFFFF; 45 | checksum += udp_length; 46 | checksum += 17; 47 | 48 | for (i=offset; i<(max&(~1)); i += 2) 49 | checksum += px[i]<<8 | px[i+1]; 50 | if (i < max) { 51 | checksum += px[i]<<8; 52 | } 53 | checksum = (checksum&0xFFFF) + (checksum>>16); 54 | if (checksum != 0xFFFF) 55 | return; 56 | } 57 | 58 | offset += 8; 59 | 60 | /* 61 | * 'destination port' 62 | */ 63 | switch (frame->port_dst) { 64 | case 53: 65 | proto_dns_parse(frame->dns, px, offset, max); 66 | if (frame->dns->is_valid) 67 | frame->net_protocol = NET_DNS; 68 | } 69 | } 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/rawsock-pfring.c: -------------------------------------------------------------------------------- 1 | /* 2 | PF_RING compatibility layer 3 | 4 | In order to avoid special build hassle, this code links to PF_RING at 5 | runtime instead compiletime. That means you can compile this code 6 | BEFORE installing and building PF_RING. 7 | 8 | */ 9 | #include "rawsock-pfring.h" 10 | #include "string_s.h" 11 | #include "logger.h" 12 | 13 | struct PFRING PFRING; 14 | 15 | #if defined(__linux__) 16 | #include 17 | #endif 18 | 19 | /*************************************************************************** 20 | * This checks whether the "pf_ring" driver is installed. 21 | ***************************************************************************/ 22 | int 23 | PFRING_is_installed() 24 | { 25 | #if defined(__linux__) 26 | FILE *fp; 27 | int err; 28 | char line[256]; 29 | int found = 0; 30 | 31 | err = fopen_s(&fp, "/proc/modules", "rb"); 32 | if (err) 33 | return 0; 34 | 35 | while (fgets(line, sizeof(line), fp)) { 36 | if (memcmp(line, "pf_ring ", 8) == 0) { 37 | found = 1; 38 | LOG_DBG(C_NETWORK, 2, "pfring: found 'pf_ring' driver\n"); 39 | } 40 | if (memcmp(line, "ixgbe ", 6) == 0) { 41 | LOG_DBG(C_NETWORK, 2, "pfring: found 'ixgbe' driver\n"); 42 | } 43 | if (memcmp(line, "e1000e ", 8) == 0) { 44 | LOG_DBG(C_NETWORK, 2, "pfring: found 'e1000e' driver\n"); 45 | } 46 | } 47 | fclose(fp); 48 | return found; 49 | #else 50 | return 0; 51 | #endif 52 | } 53 | 54 | 55 | /*************************************************************************** 56 | ***************************************************************************/ 57 | int PFRING_init() 58 | { 59 | #if defined(__linux__) 60 | void *h; 61 | int err = 0; 62 | LOG_DBG(C_NETWORK, 6, "pfring: initializing subsystem\n"); 63 | LOG_DBG(C_NETWORK, 6, "pfring: looking for 'libpfring.so'\n"); 64 | h = dlopen("libpfring.so", RTLD_LAZY); 65 | if (h == NULL) { 66 | LOG_DBG(C_NETWORK, 2, "pfring: error: dlopen('libpfring.so'): %s\n", strerror_x(errno)); 67 | return 0; 68 | } else 69 | LOG_DBG(C_NETWORK, 2, "pfring: found 'libpfring.so'!\n"); 70 | 71 | #define LOADSYM(name) if ((PFRING.name = dlsym(h, "pfring_"#name)) == 0) {LOG_DBG(C_NETWORK, 2, "pfring_%s: not found in 'libpfring.so': %s\n", #name, strerror_x(errno));err=1;} 72 | LOADSYM(open); 73 | LOADSYM(close); 74 | LOADSYM(enable_ring); 75 | LOADSYM(send); 76 | LOADSYM(recv); 77 | LOADSYM(poll); 78 | LOADSYM(version); 79 | LOADSYM(set_direction); 80 | LOADSYM(set_application_name); 81 | //LOADSYM(get_bound_device); 82 | 83 | if (err) { 84 | memset(&PFRING, 0, sizeof(PFRING)); 85 | LOG_DBG(C_NETWORK, 2, "pfring: failed to load\n"); 86 | } else { 87 | LOG_DBG(C_NETWORK, 2, "pfring: successfully loaded PF_RING API\n"); 88 | 89 | if (!PFRING_is_installed()) { 90 | LOG_ERR(C_NETWORK, 0, "pfring: ERROR: 'pf_ring' driver module not found!!!!!\n"); 91 | } else 92 | LOG_INFO(C_NETWORK, "pfring: found 'pf_ring' driver module\n"); 93 | } 94 | 95 | #endif 96 | return 0; 97 | } 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/rawsock-pfring.h: -------------------------------------------------------------------------------- 1 | #ifndef RAWSOCK_PFRING_H 2 | #define RAWSOCK_PFRING_H 3 | #include 4 | #include 5 | 6 | /* 7 | * Various PF_RING defines 8 | */ 9 | 10 | typedef enum { 11 | rx_and_tx_direction = 0, 12 | rx_only_direction, 13 | tx_only_direction 14 | } packet_direction; 15 | struct pfring_pkthdr { 16 | struct xtimeval { 17 | long tv_sec; 18 | long tv_usec; 19 | } ts; 20 | unsigned caplen; 21 | unsigned len; 22 | /* only filled in if PF_RING_LONG_HEADER set */ 23 | unsigned char extended_hdr[512]; 24 | }; 25 | #define PF_RING_ERROR_GENERIC -1 26 | #define PF_RING_ERROR_INVALID_ARGUMENT -2 27 | #define PF_RING_ERROR_NO_PKT_AVAILABLE -3 28 | #define PF_RING_ERROR_NO_TX_SLOT_AVAILABLE -4 29 | #define PF_RING_ERROR_WRONG_CONFIGURATION -5 30 | #define PF_RING_ERROR_END_OF_DEMO_MODE -6 31 | #define PF_RING_ERROR_NOT_SUPPORTED -7 32 | #define PF_RING_ERROR_INVALID_LIB_VERSION -8 33 | #define PF_RING_ERROR_UNKNOWN_ADAPTER -9 34 | #define PF_RING_ERROR_NOT_ENOUGH_MEMORY -10 35 | #define PF_RING_ERROR_INVALID_STATUS -11 36 | #define PF_RING_DNA_SYMMETRIC_RSS 1 << 0 37 | #define PF_RING_REENTRANT 1 << 1 38 | #define PF_RING_LONG_HEADER 1 << 2 39 | #define PF_RING_PROMISC 1 << 3 40 | #define PF_RING_TIMESTAMP 1 << 4 41 | #define PF_RING_HW_TIMESTAMP 1 << 5 42 | #define PF_RING_RX_PACKET_BOUNCE 1 << 6 43 | #define PF_RING_DNA_FIXED_RSS_Q_0 1 << 7 44 | #define PF_RING_STRIP_HW_TIMESTAMP 1 << 8 45 | #define PF_RING_DO_NOT_PARSE 1 << 9 /* parsing already disabled in zero-copy */ 46 | #define PF_RING_DO_NOT_TIMESTAMP 1 << 10 /* sw timestamp already disabled in zero-copy */ 47 | 48 | 49 | /* 50 | * function prototypes 51 | */ 52 | typedef struct pfring*(*PFRING_OPEN)( 53 | const char *device_name, 54 | unsigned caplen, 55 | unsigned flags); 56 | typedef void (*PFRING_CLOSE)(struct pfring *ring); 57 | typedef int (*PFRING_ENABLE_RING)(struct pfring *ring); 58 | typedef int (*PFRING_SEND)(struct pfring *ring, 59 | const unsigned char *buffer, 60 | unsigned buffer_length, 61 | unsigned char flush_packet); 62 | typedef int (*PFRING_RECV)(struct pfring *ring, 63 | unsigned char** buffer, 64 | unsigned buffer_length, 65 | struct pfring_pkthdr *hdr, 66 | unsigned char wait_for_incoming_packet); 67 | typedef int (*PFRING_POLL)(struct pfring *ring, unsigned wait_duration); 68 | typedef int (*PFRING_VERSION)(struct pfring *ring, unsigned *version); 69 | typedef int (*PFRING_SET_DIRECTION)(struct pfring *ring, int direction); 70 | typedef int (*PFRING_SET_APPLICATION_NAME)(struct pfring *ring, char *name); 71 | typedef int (*PFRING_GET_BOUND_DEVICE)(struct pfring *ring, unsigned char mac_address[6]); 72 | 73 | /* 74 | * scoped object 75 | */ 76 | extern struct PFRING { 77 | PFRING_OPEN open; 78 | PFRING_CLOSE close; 79 | PFRING_ENABLE_RING enable_ring; 80 | PFRING_SEND send; 81 | PFRING_RECV recv; 82 | PFRING_POLL poll; 83 | PFRING_VERSION version; 84 | PFRING_SET_DIRECTION set_direction; 85 | PFRING_SET_APPLICATION_NAME set_application_name; 86 | PFRING_GET_BOUND_DEVICE get_bound_device; 87 | } PFRING; 88 | 89 | /* 90 | * call this to load the library 91 | */ 92 | int PFRING_init(); 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/rawsock.c: -------------------------------------------------------------------------------- 1 | #include "rawsock.h" 2 | #include "adapter.h" 3 | #include "rawsock-pfring.h" 4 | #include "adapter-pcaplive.h" 5 | #include "logger.h" 6 | 7 | #define SENDQ_SIZE (65536 * 8) 8 | 9 | 10 | /*************************************************************************** 11 | * wrapper for libpcap's sendpacket 12 | * 13 | * PORTABILITY: WINDOWS and PF_RING 14 | * For performance, Windows and PF_RING can queue up multiple packets, then 15 | * transmit them all in a chunk. If we stop and wait for a bit, we need 16 | * to flush the queue to force packets to be transmitted immediately. 17 | ***************************************************************************/ 18 | void 19 | rawsock_send_packet(struct Adapter *adapter, 20 | struct Thread *thread, 21 | struct Packet *pkt) 22 | { 23 | const unsigned char *packet = pkt->buf; 24 | unsigned length = pkt->offset; 25 | unsigned flush = 1; 26 | 27 | if (adapter == 0) 28 | return; 29 | 30 | 31 | /* PF_RING */ 32 | if (adapter->ring) { 33 | int err = PF_RING_ERROR_NO_TX_SLOT_AVAILABLE; 34 | 35 | while (err == PF_RING_ERROR_NO_TX_SLOT_AVAILABLE) { 36 | err = PFRING.send(adapter->ring, packet, length, (unsigned char)flush); 37 | } 38 | if (err < 0) 39 | LOG_ERR(C_NETWORK, "pfring:xmit: ERROR %d\n", err); 40 | return; 41 | } 42 | 43 | /* WINDOWS PCAP */ 44 | if (adapter->sendq) { 45 | int err; 46 | struct pcap_pkthdr hdr; 47 | hdr.len = length; 48 | hdr.caplen = length; 49 | 50 | err = pcap.sendqueue_queue(adapter->sendq, &hdr, packet); 51 | if (err) { 52 | //printf("sendpacket() failed %d\n", x); 53 | //for (;;) 54 | pcap.sendqueue_transmit(adapter->pcap, adapter->sendq, 0); 55 | //printf("pcap_send_queue)() returned %u\n", x); 56 | pcap.sendqueue_destroy(adapter->sendq); 57 | adapter->sendq = pcap.sendqueue_alloc(SENDQ_SIZE); 58 | pcap.sendqueue_queue(adapter->sendq, &hdr, packet); 59 | //("sendpacket() returned %d\n", x); 60 | //exit(1); 61 | } else 62 | ; //printf("+%u\n", count++); 63 | if (flush) { 64 | pcap.sendqueue_transmit(adapter->pcap, adapter->sendq, 0); 65 | 66 | /* Dude, I totally forget why this step is necessary. I vaguely 67 | * remember there's a good reason for it though */ 68 | pcap.sendqueue_destroy(adapter->sendq); 69 | adapter->sendq = pcap.sendqueue_alloc(SENDQ_SIZE); 70 | } 71 | return; 72 | } 73 | 74 | /* LIBPCAP */ 75 | if (adapter->pcap) 76 | pcap.sendpacket(adapter->pcap, packet, length); 77 | 78 | return; 79 | } 80 | 81 | /*************************************************************************** 82 | ***************************************************************************/ 83 | int rawsock_recv_packet( 84 | struct Adapter *adapter, 85 | unsigned *length, 86 | unsigned *secs, 87 | unsigned *usecs, 88 | const unsigned char **packet) 89 | { 90 | if (adapter->ring) { 91 | struct pfring_pkthdr hdr; 92 | int err; 93 | 94 | again: 95 | err = PFRING.recv(adapter->ring, 96 | (unsigned char**)packet, 97 | 0, /* zero-copy */ 98 | &hdr, 99 | 0 /* return immediately */ 100 | ); 101 | if (err == PF_RING_ERROR_NO_PKT_AVAILABLE || hdr.caplen == 0) { 102 | PFRING.poll(adapter->ring, 1); 103 | goto again; 104 | } 105 | if (err) 106 | return 1; 107 | 108 | *length = hdr.caplen; 109 | *secs = hdr.ts.tv_sec; 110 | *usecs = hdr.ts.tv_usec; 111 | 112 | } else if (adapter->pcap) { 113 | struct pcap_pkthdr hdr; 114 | 115 | 116 | *packet = pcap.next(adapter->pcap, &hdr); 117 | 118 | if (*packet == NULL) 119 | return 1; 120 | 121 | *length = hdr.caplen; 122 | *secs = hdr.ts.tv_sec; 123 | *usecs = hdr.ts.tv_usec; 124 | } 125 | 126 | 127 | return 0; 128 | } 129 | 130 | 131 | /*************************************************************************** 132 | ***************************************************************************/ 133 | void 134 | rawsock_init() 135 | { 136 | /* Once-per-process: initialize 'libpcap' */ 137 | pcaplive_init(); 138 | 139 | #if defined(__linux) 140 | PFRING_init(); 141 | #endif 142 | return; 143 | } 144 | -------------------------------------------------------------------------------- /src/rawsock.h: -------------------------------------------------------------------------------- 1 | /* 2 | raw sockets stuff 3 | */ 4 | #ifndef RAWSOCK_H 5 | #define RAWSOCK_H 6 | #include 7 | struct Packet; 8 | struct Thread; 9 | 10 | void 11 | rawsock_init(); 12 | 13 | /** 14 | * Does an "open" on the network adapter. What actually happens depends upon 15 | * the operating system and drivers that we are using, but usually this just 16 | * calls "pcap_open()" 17 | * @param adapter_name 18 | * The name of the adapter, like "eth0" or "dna1". 19 | * @param is_pfring 20 | * Whether we should attempt to use the PF_RING driver (Linux-only) 21 | * @param is_sendq 22 | * Whether we should attempt to use a ring-buffer for sending packets. 23 | * Currently Windows-only, but it'll be enabled for Linux soon. Big 24 | * performance gains for Windows, but insignificant performance 25 | * difference for Linux. 26 | * @param is_packet_trace 27 | * Whether then Nmap --packet-trace option was set on the command-line 28 | * @param is_offline 29 | * Whether the --offline parameter was set on the command-line. If so, 30 | * then no network adapter will actually be opened. 31 | * @return 32 | * a fully instantiated network adapter 33 | */ 34 | struct Adapter * 35 | rawsock_init_adapter(const char *adapter_name, 36 | unsigned is_pfring, 37 | unsigned is_sendq, 38 | unsigned is_packet_trace, 39 | unsigned is_offline); 40 | 41 | void rawsock_list_adapters(); 42 | 43 | 44 | const char *rawsock_win_name(const char *ifname); 45 | 46 | int rawsock_is_adapter_names_equal(const char *lhs, const char *rhs); 47 | 48 | void 49 | rawsock_send_packet(struct Adapter *adapter, 50 | struct Thread *thread, 51 | struct Packet *pkt); 52 | 53 | int rawsock_recv_packet( 54 | struct Adapter *adapter, 55 | unsigned *length, 56 | unsigned *secs, 57 | unsigned *usecs, 58 | const unsigned char **packet); 59 | 60 | 61 | void rawsock_ignore_transmits(struct Adapter *adapter, const unsigned char *adapter_mac); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/resolver.h: -------------------------------------------------------------------------------- 1 | #ifndef RESOLVER_H 2 | #define RESOLVER_H 3 | #include "domainname.h" 4 | 5 | 6 | struct Thread; 7 | struct Catalog; 8 | struct DNS_OutgoingResponse; 9 | struct DNS_Incoming; 10 | 11 | 12 | 13 | /** 14 | * !!!!! IMPORTANT !!!!!! 15 | * 16 | * THIS IS THE CENTER OF THE PROGRAM, THE PARTS THAT TAKES AN INCOMING REQUEST 17 | * CAN RESOLVES INTO THE RESULT 18 | */ 19 | void resolver_algorithm(const struct Catalog *catalog, 20 | struct DNS_OutgoingResponse *response, 21 | const struct DNS_Incoming *request); 22 | 23 | /** 24 | * Call this before calling 'resolver_algorithm' to initialize the 25 | * response structure 26 | */ 27 | void resolver_init(struct DNS_OutgoingResponse *response, 28 | const unsigned char *query_name, 29 | unsigned query_name_length, 30 | int query_type, 31 | unsigned id, 32 | unsigned opcode); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/robdns.h: -------------------------------------------------------------------------------- 1 | #ifndef ROBDNS_H 2 | #define ROBDNS_H 3 | 4 | /** 5 | * Configuration settings for the server 6 | */ 7 | struct RobDNS { 8 | int op; 9 | 10 | struct { 11 | char ifname[256]; 12 | struct Adapter *adapter; 13 | unsigned adapter_ip; 14 | unsigned adapter_port; 15 | unsigned char adapter_mac[6]; 16 | unsigned char router_mac[6]; 17 | } nic[8]; 18 | unsigned nic_count; 19 | 20 | unsigned is_pfring:1; /* --pfring */ 21 | unsigned is_sendq:1; /* --sendq */ 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/selftest-parsefast.c: -------------------------------------------------------------------------------- 1 | /* 2 | SELFTEST - fast parser 3 | 4 | This tests the parser parsing too fast having to catch 5 | */ 6 | #include "zonefile-parse.h" 7 | #include "zonefile-load.h" 8 | #include "success-failure.h" 9 | #include "unusedparm.h" 10 | #include "db.h" 11 | #include "db-zone.h" 12 | #include "string_s.h" 13 | #include "util-realloc2.h" 14 | #include 15 | #include 16 | 17 | extern void 18 | LOAD(const char *string, struct ZoneFileParser *parser, struct Catalog *db); 19 | 20 | unsigned myrand(unsigned *seed) 21 | { 22 | *seed = *seed * 1103515245 + 12345; 23 | return *seed; 24 | } 25 | 26 | int 27 | selftest2(int argc, char *argv[]) 28 | { 29 | struct ZoneFileParser *parser; 30 | struct Catalog *catalog; 31 | static const struct DomainPointer example_origin = {(const unsigned char*)"\7example\3com",12}; 32 | size_t zonetext_size = 256*1024*1024; 33 | size_t zonetext_offset = 0; 34 | unsigned char *zonetext; 35 | unsigned seed = 0; 36 | int result; 37 | 38 | 39 | UNUSEDPARM(argc); 40 | UNUSEDPARM(argv); 41 | 42 | 43 | catalog = catalog_create(); 44 | parser = zonefile_begin( 45 | example_origin, /* origin */ 46 | 60, /* TTL */ 47 | zonetext_size, /* filesize */ 48 | "", /* filename */ 49 | zonefile_load, /* callback */ 50 | catalog, /* callback data */ 51 | 0 52 | ); 53 | 54 | LOAD("$TTL 60\r\n" 55 | "example.com. IN SOA ns hostmaster (\r\n" 56 | " 2003080800 ; sn = serial number\r\n" 57 | " 172800 ; ref = refresh = 2d\r\n" 58 | " 15m ; ret = update retry = 15m\r\n" 59 | " 1209600 ; ex = expiry = 2w\r\n" 60 | " 1H ; nx = nxdomain ttl = 1h\r\n" 61 | " )\r\n", parser, catalog); 62 | LOAD("foo IN A 1.2.3.4\n", parser, catalog); 63 | 64 | 65 | /* 66 | * Create a huge number of entries 67 | */ 68 | zonetext = MALLOC2(zonetext_size); 69 | if (zonetext == 0) 70 | return -1; 71 | for (;;) { 72 | char tmp[256]; 73 | switch (myrand(&seed)&0xF) { 74 | case 0: 75 | sprintf_s(tmp, sizeof(tmp), "%08x TXT \"%08X%08x%08x\"\n", 76 | myrand(&seed)&0xFFFF, myrand(&seed), myrand(&seed), myrand(&seed)); 77 | break; 78 | case 1: 79 | sprintf_s(tmp, sizeof(tmp), "%08x%08x CNAME %08x\n", 80 | myrand(&seed), myrand(&seed), myrand(&seed)); 81 | break; 82 | default: 83 | sprintf_s(tmp, sizeof(tmp), "%08x A %u.%u.%u.%u\n", 84 | myrand(&seed), 85 | myrand(&seed)&0xFF, 86 | myrand(&seed)&0xFF, 87 | myrand(&seed)&0xFF, 88 | myrand(&seed)&0xFF 89 | ); 90 | } 91 | if (zonetext_offset + strlen(tmp) + 1 < zonetext_size) { 92 | memcpy(&zonetext[zonetext_offset], tmp, strlen(tmp)); 93 | zonetext_offset += strlen(tmp); 94 | } else 95 | break; 96 | } 97 | zonetext[zonetext_offset] = '\0'; 98 | 99 | 100 | 101 | { 102 | clock_t start, stop; 103 | double elapsed; 104 | 105 | start = clock(); 106 | LOAD((const char *)zonetext, parser, catalog); 107 | stop = clock(); 108 | elapsed = (stop-start)*1.0/CLOCKS_PER_SEC; 109 | 110 | 111 | printf("%5.2f-sec %5.2f-MBps\n", elapsed, zonetext_offset/(1024.0*1024.0)/elapsed); 112 | } 113 | 114 | 115 | 116 | result = zonefile_end(parser); 117 | if (result != Success) { 118 | fprintf(stderr, "error: failed\n"); 119 | return Failure; 120 | } 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | return Success; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /src/selftest.h: -------------------------------------------------------------------------------- 1 | #ifndef SELFTEST_H 2 | #define SELFTEST_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | int selftest(int argc, char *argv[]); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif 12 | #endif -------------------------------------------------------------------------------- /src/smack.h: -------------------------------------------------------------------------------- 1 | #ifndef _SMACK_H 2 | #define _SMACK_H 3 | #include 4 | 5 | #define SMACK_NOT_FOUND ((size_t)(~0)) 6 | 7 | /** 8 | * "Anchor" flags are specified only for patterns that must 9 | * match at the start of input, at the end, or both. 10 | * These are equivalent to the regex specifiers "^" and "$" 11 | * respectively. 12 | */ 13 | enum { 14 | SMACK_ANCHOR_BEGIN = 0x01, 15 | SMACK_ANCHOR_END = 0x02, 16 | SMACK_SNMP_HACK = 0x04, 17 | }; 18 | 19 | enum { 20 | SMACK_CASE_SENSITIVE = 0, 21 | SMACK_CASE_INSENSITIVE = 1, 22 | }; 23 | 24 | 25 | /** 26 | * This is the function that will be called whenever SMACK 27 | * finds a pattern. 28 | */ 29 | typedef int (*FOUND_CALLBACK)(size_t id, int offset, void *data); 30 | 31 | 32 | /** 33 | * Create the Aho-Corasick search object. After creation, you can start 34 | * adding patterns, but you cannot use it for searching until you've 35 | * compiled the patterns. 36 | */ 37 | struct SMACK * 38 | smack_create(const char *name, unsigned nocase); 39 | 40 | 41 | /** 42 | * Cleans up and frees an object created with smack_create(). 43 | */ 44 | void 45 | smack_destroy(struct SMACK *smack); 46 | 47 | 48 | /** 49 | * Registers a pattern with the search engine. The 'smack' object 50 | * must have been created with 'smack_create()', but you must not 51 | * have yet called 'smack_compile()' to compile the patterns. The 52 | * "id" field can contain a pointer (size_t is 64-bit on 64-bit 53 | * systems). 54 | */ 55 | void 56 | smack_add_pattern( struct SMACK * smack, 57 | const void * pattern, 58 | unsigned pattern_length, 59 | size_t id, 60 | unsigned flags); 61 | 62 | /** 63 | * You call this function after you have registered all the patterns 64 | * using 'smack_add_pattern()' in order to compile the state-machine. 65 | * Don't use the state-machine with 'smack_search()' until you have 66 | * compiled all the patterns with this function. 67 | */ 68 | void 69 | smack_compile(struct SMACK *smack); 70 | 71 | 72 | /** 73 | * Run the state-machine, searching for the compiled patterns within 74 | * a block of data/text. This can only be called after "smack_compile()" 75 | * has created the state-machine. 76 | * 77 | * If the input is fragmented, this function can be called repeatedly 78 | * for each fragment. Patterns that cross fragments will still be 79 | * detected. 80 | * 81 | * The caller must initialize "*state" to zero "0" before running this 82 | * function on the first fragment, but must thereafter leave it 83 | * unchanged between fragments. (If the caller resets the *state variable 84 | * to zero between each fragment, then patterns that cross fragment 85 | * boundaries cannot be detected). 86 | */ 87 | unsigned 88 | smack_search( struct SMACK * smack, 89 | const void * px, 90 | unsigned length, 91 | FOUND_CALLBACK cb_found, 92 | void * cb_data, 93 | unsigned * state); 94 | 95 | size_t 96 | smack_search_next( struct SMACK * smack, 97 | unsigned * state, 98 | const void * px, 99 | unsigned * offset, 100 | unsigned length 101 | ); 102 | 103 | /** 104 | * If there are multiple matches at the current state, returns the next 105 | * one. Otherwise, returns NOT_FOUND. Used with "smack_search_next()". 106 | */ 107 | size_t 108 | smack_next_match( struct SMACK * smack, 109 | unsigned * state); 110 | 111 | /** 112 | * Call this after search is done. This is not generally necessary. 113 | * It's only purpose is to detect patterns that have the 114 | * SMACK_ANCHOR_END flag set. If no pattern has that flag, then 115 | * this function will do nothing. 116 | */ 117 | unsigned 118 | smack_search_end( struct SMACK * smack, 119 | FOUND_CALLBACK cb_found, 120 | void * cb_data, 121 | unsigned * state); 122 | 123 | 124 | 125 | /** 126 | * Runs a regression test on the module to make sure it's compiled 127 | * correctly for the current platform. 128 | * 129 | * @return 130 | * zero if regression test succeeds, non-zero on failure 131 | */ 132 | int 133 | smack_selftest(void); 134 | 135 | int 136 | smack_benchmark(void); 137 | 138 | #endif /*_SMACK_H*/ 139 | -------------------------------------------------------------------------------- /src/smackqueue.c: -------------------------------------------------------------------------------- 1 | #include "smackqueue.h" 2 | #include 3 | #include 4 | #include 5 | 6 | /**************************************************************************** 7 | * Build a queue so that we can do a breadth-first enumeration of the 8 | * sub-patterns 9 | ****************************************************************************/ 10 | struct QueueElement 11 | { 12 | unsigned m_data; 13 | struct QueueElement *m_next; 14 | }; 15 | struct Queue 16 | { 17 | struct QueueElement *m_head; 18 | struct QueueElement *m_tail; 19 | }; 20 | 21 | struct Queue * 22 | queue_create(void) 23 | { 24 | struct Queue *queue; 25 | queue = (struct Queue *)malloc(sizeof(*queue)); 26 | if (queue == NULL) { 27 | fprintf(stderr, "%s: out of memory error\n", "smack"); 28 | exit(1); 29 | } 30 | memset(queue, 0, sizeof(*queue)); 31 | return queue; 32 | } 33 | 34 | void 35 | queue_destroy(struct Queue * queue) 36 | { 37 | if (queue == NULL) 38 | return; 39 | while (queue_has_more_items(queue)) 40 | dequeue(queue); 41 | free(queue); 42 | } 43 | 44 | void 45 | enqueue(struct Queue *queue, unsigned data) 46 | { 47 | struct QueueElement *element; 48 | 49 | element = (struct QueueElement *)malloc(sizeof (struct QueueElement)); 50 | if (element == NULL) { 51 | fprintf(stderr, "%s: out of memory error\n", "smack"); 52 | exit(1); 53 | } 54 | 55 | if (queue->m_head == NULL) { 56 | /* If nothing in the queue, initialize the queue with the 57 | * first data */ 58 | queue->m_head = element; 59 | } else { 60 | /* Else, add the data to the the tail of the queue */ 61 | queue->m_tail->m_next = element; 62 | } 63 | 64 | element->m_data = data; 65 | element->m_next = NULL; 66 | queue->m_tail = element; 67 | } 68 | 69 | unsigned 70 | dequeue(struct Queue *queue) 71 | { 72 | if (queue->m_head == NULL) 73 | return 0; 74 | else { 75 | struct QueueElement *element; 76 | unsigned result; 77 | 78 | element = queue->m_head; 79 | result = element->m_data; 80 | queue->m_head = element->m_next; 81 | 82 | free(element); 83 | return result; 84 | } 85 | } 86 | 87 | unsigned queue_has_more_items(struct Queue * queue) 88 | { 89 | return queue->m_head != NULL; 90 | } 91 | -------------------------------------------------------------------------------- /src/smackqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef SMACKQUEUE_H 2 | #define SMACKQUEUE_H 3 | 4 | struct Queue * 5 | queue_create(void); 6 | 7 | 8 | void 9 | queue_destroy(struct Queue *queue); 10 | 11 | 12 | void 13 | enqueue(struct Queue *queue, unsigned data); 14 | 15 | 16 | unsigned 17 | dequeue(struct Queue *queue); 18 | 19 | 20 | unsigned 21 | queue_has_more_items(struct Queue *queue); 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/source.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The source of the input, for printing error messages 4 | */ 5 | #ifndef SOURCE_H 6 | #define SOURCE_H 7 | 8 | struct InputSource 9 | { 10 | const char *filename; 11 | unsigned line_number; 12 | unsigned error_count; 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/string_s.c: -------------------------------------------------------------------------------- 1 | /* 2 | safe C library functions 3 | 4 | This upgrades unsafe C functions like "strcpy()" to safer equivelents, 5 | like "strcpy_s()". 6 | 7 | NOTE: This is for maintaining a policy of "no unsafe functions" 8 | */ 9 | #include "string_s.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * fopen_s 17 | */ 18 | #if defined(__GNUC__) || _MSC_VER == 1200 19 | errno_t fopen_s(FILE **pFile, const char *filename, const char *mode) 20 | { 21 | if (pFile == NULL || filename == NULL || mode == NULL) 22 | return EINVAL; 23 | *pFile = fopen(filename, mode); 24 | if (*pFile != NULL) 25 | return 0; 26 | else 27 | return errno; 28 | } 29 | #endif 30 | 31 | /** 32 | * Case-insensitive memcmp() 33 | */ 34 | #ifdef __GNUC__ 35 | int 36 | memcasecmp(const void *lhs, const void *rhs, int length) 37 | { 38 | int i; 39 | for (i=0; i= sizeof_dst) { 68 | dst[0] = 0; 69 | return ERANGE; 70 | } else 71 | dst[i] = src[i]; 72 | } 73 | if (i >= sizeof_dst) { 74 | dst[0] = 0; 75 | return ERANGE; 76 | } else 77 | dst[i] = src[i]; 78 | 79 | return 0; 80 | } 81 | 82 | errno_t localtime_s(struct tm* _tm, const time_t *time) 83 | { 84 | struct tm *x; 85 | 86 | x = localtime(time); 87 | memcpy(_tm, x, sizeof(*_tm)); 88 | 89 | return 0; 90 | } 91 | errno_t gmtime_s(struct tm* _tm, const time_t *time) 92 | { 93 | struct tm *x; 94 | 95 | x = gmtime(time); 96 | memcpy(_tm, x, sizeof(*_tm)); 97 | 98 | return 0; 99 | } 100 | #endif 101 | 102 | 103 | /* 104 | * I don't understand why Microsoft says this function is unsafe, so 105 | * do it anyway 106 | */ 107 | const char *strerror_x(int x) 108 | { 109 | #ifdef _MSC_VER 110 | #pragma warning(disable: 4996) 111 | #endif 112 | #undef strerror 113 | return strerror(x); 114 | } 115 | -------------------------------------------------------------------------------- /src/string_s.h: -------------------------------------------------------------------------------- 1 | /* 2 | safe "string" functions, like Microsoft's 3 | 4 | This is for the "safe" clib functions, where things like "strcpy()" is 5 | replaced with a safer version of the function, like "strcpy_s()". Since 6 | these things are non-standard, compilers deal with them differently. 7 | 8 | Reference: 9 | http://msdn.microsoft.com/en-us/library/bb288454.aspx 10 | */ 11 | #ifndef STRCPY_S 12 | #define STRCPY_S 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #undef strcpy 21 | #define strcpy STRCPY_FUNCTION_IS_BAD 22 | 23 | #undef strncpy 24 | #define strncpy STRNCPY_FUNCTION_IS_BAD 25 | 26 | #undef strcat 27 | #define strcat STRCAT_FUNCTION_IS_BAD 28 | 29 | #undef strncat 30 | #define strncat STRNCAT_FUNCTION_IS_BAD 31 | 32 | #undef sprintf 33 | #define sprintf SPRINTF_FUNCTION_IS_BAD 34 | 35 | #undef vsprintf 36 | #define vsprintf VSPRINTF_FUNCTION_IS_BAD 37 | 38 | #undef strtok 39 | #define strtok STRTOK_FUNCTION_IS_BAD 40 | 41 | #undef gets 42 | #define gets GETS_FUNCTION_IS_BAD 43 | 44 | #undef scanf 45 | #define scanf SCANF_FUNCTION_IS_BAD 46 | 47 | #undef sscanf 48 | #define sscanf SSCANF_FUNCTION_IS_BAD 49 | 50 | #undef itoa 51 | #define itoa ITOA_FUNCTION_IS_BAD 52 | 53 | #undef strerror 54 | #define strerror STRERROR_FUNCTION_IS_BAD 55 | 56 | const char *strerror_x(int x); 57 | 58 | #if defined(_MSC_VER) && (_MSC_VER == 1600) 59 | /*Visual Studio 2010*/ 60 | # include 61 | # include 62 | # define strcasecmp _stricmp 63 | # define memcasecmp _memicmp 64 | # define strncasecmp _strnicmp 65 | 66 | # ifndef PRIu64 67 | # define PRIu64 "llu" 68 | # define PRId64 "lld" 69 | # define PRIx64 "llx" 70 | # endif 71 | 72 | 73 | #elif defined(_MSC_VER) && (_MSC_VER == 1200) 74 | /* Visual Studio 6.0 */ 75 | # define sprintf_s _snprintf 76 | # define strcasecmp _stricmp 77 | # define memcasecmp _memicmp 78 | # define vsprintf_s _vsnprintf 79 | typedef int errno_t; 80 | errno_t fopen_s(FILE **fp, const char *filename, const char *mode); 81 | 82 | #elif defined(__GNUC__) && (__GNUC__ == 4) 83 | /* GCC 4 */ 84 | # define sprintf_s snprintf 85 | # define vsprintf_s vsnprintf 86 | int memcasecmp(const void *lhs, const void *rhs, int length); 87 | typedef int errno_t; 88 | errno_t fopen_s(FILE **fp, const char *filename, const char *mode); 89 | errno_t strcpy_s(char *dst, size_t sizeof_dst, const char *src); 90 | errno_t localtime_s(struct tm* _tm, const time_t *time); 91 | errno_t gmtime_s(struct tm* _tm, const time_t *time); 92 | #undef strerror 93 | 94 | #ifdef WIN32 95 | # ifndef PRIu64 96 | # define PRIu64 "I64u" 97 | # define PRId64 "I64d" 98 | # define PRIx64 "I64x" 99 | # endif 100 | #else 101 | # include 102 | #endif 103 | 104 | #else 105 | # error unknown compiler 106 | #endif 107 | 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/success-failure.h: -------------------------------------------------------------------------------- 1 | #ifndef SUCCESS_FAILURE_H 2 | #define SUCCESS_FAILURE_H 3 | 4 | enum SuccessFailure {Failure=0, Success=1}; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/thread-atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_ATOMIC_H 2 | #define THREAD_ATOMIC_H 3 | 4 | #if defined(_MSC_VER) 5 | #include 6 | #define thread_compare_and_swap(value, old_value, new_value) (_InterlockedCompareExchange((long*)(value), new_value, old_value) == old_value) 7 | 8 | #elif defined(__GNUC__) 9 | #define thread_compare_and_swap(value, old_value, new_value) (__sync_bool_compare_and_swap((value), old_value, new_value)) 10 | #endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | struct Catalog; 8 | 9 | struct Thread 10 | { 11 | struct Catalog *catalog_run; 12 | unsigned ip_id; 13 | 14 | struct Statistics { 15 | uint64_t ip_bad_checksum; 16 | uint64_t icmp_bad_checksum; 17 | uint64_t icmp_bad_type; 18 | } stats; 19 | 20 | void *userdata; 21 | }; 22 | 23 | 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | #endif 29 | -------------------------------------------------------------------------------- /src/unusedparm.h: -------------------------------------------------------------------------------- 1 | #ifndef UNUSEDPARM 2 | #if defined(_MSC_VER) 3 | #define UNUSEDPARM(x) x 4 | #elif defined(__GNUC__) 5 | #define UNUSEDPARM(x) (void)x 6 | #endif 7 | #endif 8 | -------------------------------------------------------------------------------- /src/util-filename.c: -------------------------------------------------------------------------------- 1 | #include "util-filename.h" 2 | #include "util-keyword.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef WIN32 9 | #include /* getcwd */ 10 | #define getcwd _getcwd 11 | #else 12 | #include /* getcwd */ 13 | #endif 14 | 15 | /* use these macros, because functions like isspace() produce undefined 16 | * results for sign-extended characters */ 17 | #define my_isspace(c) isspace((c)&0xFF) 18 | #define my_isalpha(c) isalpha((c)&0xFF) 19 | #define my_isdigit(c) isdigit((c)&0xFF) 20 | 21 | /*************************************************************************** 22 | ****************************************************************************/ 23 | void 24 | combine_elements(char *result, unsigned *result_offset, unsigned result_max, 25 | unsigned prefix_length, 26 | const char *filename, unsigned in_filename_offset, unsigned filename_max) 27 | { 28 | unsigned filename_offset[1]; 29 | static const struct Keyword slash = {"/", 1}; 30 | 31 | *filename_offset = in_filename_offset; 32 | 33 | while (*filename_offset < filename_max) { 34 | struct Keyword element; 35 | 36 | /* skip duplicate //// characters */ 37 | if (filename[*filename_offset] == '\\') { 38 | (*filename_offset)++; 39 | continue; 40 | } 41 | if (filename[*filename_offset] == '/') { 42 | (*filename_offset)++; 43 | continue; 44 | } 45 | 46 | /* Grab element from input filename */ 47 | element = keyword_next_path_element(filename, filename_offset, filename_max); 48 | 49 | /* ignore "." */ 50 | if (keyword_is_equal(&element, ".")) { 51 | continue; 52 | } 53 | 54 | /* traverse "..". Keep track of the path prefix (like "c:\") and don't go 55 | * past the root even if there are too many ".." symbols */ 56 | if (keyword_is_equal(&element, "..")) { 57 | 58 | /* go backwards until "/" */ 59 | while (*result_offset > prefix_length && result[(*result_offset)-1] != '/' && result[(*result_offset)-1] != '\\') 60 | (*result_offset)--; 61 | 62 | /* go backwards past the "/" */ 63 | while ((*result_offset) > prefix_length && (result[(*result_offset)-1] == '/' || result[(*result_offset)-1] == '\\')) 64 | (*result_offset)--; 65 | 66 | /* terminate string at this point */ 67 | result[*result_offset] = '\0'; 68 | continue; 69 | } 70 | 71 | /* else, 72 | * append the right-hand element onto the left-hand element 73 | */ 74 | if (*result_offset && result[(*result_offset) - 1] != '/') 75 | keyword_append(result, result_offset, result_max, slash); 76 | keyword_append(result, result_offset, result_max, element); 77 | } 78 | } 79 | 80 | 81 | /*************************************************************************** 82 | ****************************************************************************/ 83 | char * 84 | filename_combine(const char *dirname, const char *filename) 85 | { 86 | char *result; 87 | unsigned dirname_length; 88 | unsigned filename_length; 89 | unsigned dirname_offset = 0; 90 | unsigned result_offset = 0; 91 | unsigned result_max; 92 | static const struct Keyword slash = {"/", 1}; 93 | struct Keyword prefix; 94 | unsigned prefix_length; 95 | 96 | /* Deal with empty strings*/ 97 | filename_length = (unsigned)strlen(filename); 98 | if (dirname == NULL || dirname[0] == '\0') { 99 | result = (char*)malloc(filename_length+1); 100 | if (result == NULL) 101 | exit(1); 102 | memcpy(result, filename, filename_length+1); 103 | return result; 104 | } 105 | dirname_length = (unsigned)strlen(dirname); 106 | 107 | 108 | /* Remove leading '/' on the filename */ 109 | while (filename_length && (filename[0] == '/' || filename[0] == '\\')) { 110 | filename_length--; 111 | filename++; 112 | } 113 | 114 | /* Remove trailing '/' on directory name */ 115 | while (dirname_length && (dirname[dirname_length-1] == '/' || filename[0] == '\\')) 116 | dirname_length--; 117 | 118 | /* Allocate space for the result */ 119 | result_max = dirname_length + filename_length + 2; 120 | result = (char*)malloc(result_max + 1); 121 | if (result == NULL) 122 | exit(1); 123 | 124 | /* 125 | * Get the prefix, which is something like "C:\" on Windows, 126 | * or "\\" or "//" also on Windows, or "/" on Unix 127 | */ 128 | prefix = keyword_get_file_prefix(dirname, &dirname_offset, dirname_length); 129 | keyword_append(result, &result_offset, result_max, prefix); 130 | if (result_offset && result[result_offset - 1] != '/' && result[result_offset - 1] != '\\') 131 | keyword_append(result, &result_offset, result_max, slash); 132 | prefix_length = result_offset; 133 | 134 | /* Combine elements */ 135 | combine_elements(result, &result_offset, result_max, prefix_length, dirname, dirname_offset, dirname_length); 136 | combine_elements(result, &result_offset, result_max, prefix_length, filename, 0, filename_length); 137 | 138 | 139 | return result; 140 | } 141 | 142 | /*************************************************************************** 143 | ****************************************************************************/ 144 | int 145 | filename_is_absolute(const char *filename) 146 | { 147 | if (filename == NULL || filename[0] == '\0') 148 | return 0; 149 | if (filename[0] == '/') 150 | return 1; 151 | #if WIN32 152 | if (filename[0] == '\\') 153 | return 1; 154 | if (strlen(filename) >= 3) { 155 | if (my_isalpha(filename[0]) && filename[1] == ':') { 156 | if (filename[2] == '\\' || filename[2] == '/') 157 | return 1; 158 | } 159 | } 160 | #endif 161 | return 0; 162 | } 163 | 164 | 165 | /*************************************************************************** 166 | ****************************************************************************/ 167 | char * 168 | filename_get_directory(const char *filename) 169 | { 170 | char *filename2; 171 | size_t len = strlen(filename); 172 | char *result; 173 | 174 | while (len && filename[len] != '/' && filename[len] != '\\') 175 | len--; 176 | 177 | filename2 = malloc(len+1); 178 | if (filename2 == NULL) 179 | exit(1); 180 | memcpy(filename2, filename, len+1); 181 | filename2[len] = '\0'; 182 | 183 | if (filename_is_absolute(filename2)) 184 | result = filename_combine(filename2, ""); 185 | else { 186 | char buf[512]; 187 | if (getcwd(buf, sizeof(buf)) == NULL) 188 | exit(1); 189 | result = filename_combine(buf, filename2); 190 | } 191 | free(filename2); 192 | return result; 193 | } 194 | -------------------------------------------------------------------------------- /src/util-filename.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ****************************************************************************/ 3 | #ifndef UTIL_FILENAME_H 4 | #define UTIL_FILENAME_H 5 | 6 | /* Combine directoryname with filename */ 7 | char *filename_combine(const char *dirname, const char *filename); 8 | 9 | int filename_is_absolute(const char *filename); 10 | 11 | char *filename_get_directory(const char *filename); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/util-ipaddr.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertdavidgraham/robdns/d76d2e6817ebefe240c667aecdc478d7e3fec586/src/util-ipaddr.c -------------------------------------------------------------------------------- /src/util-ipaddr.h: -------------------------------------------------------------------------------- 1 | #ifndef RULE_PARSE_ADDRESS_H 2 | #define RULE_PARSE_ADDRESS_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | #include 8 | 9 | /** 10 | * An IP (version 4 or version 6) address that we parsed out of a Snort 11 | * rule 12 | */ 13 | struct ParsedIpAddress { 14 | unsigned char address[16]; /* big enough for IPv6 and IPv4 */ 15 | unsigned char prefix_length; /* CIDR-style /prefix */ 16 | unsigned char version; /* '4' or '6' */ 17 | }; 18 | 19 | /* Set the offset to the character that caused the error before returning */ 20 | #define RETURN_ERR(n) *offset=i,n 21 | 22 | /** 23 | * Attempt to parse an address (IPv4 or IPv6) from the input, including a CIDR-style 24 | * prefix at the end. 25 | * @params 26 | * px 27 | * Points to the input text field. 28 | * *offset [IN/OUT] 29 | * The starting offset in the text field were we should parse the address, 30 | * and after the function, points to the first character after the address, 31 | * or in the case of error, the character that caused the error. 32 | * length 33 | * The length of the entire text field, which will likely be much longer 34 | * than the address. There is likely more text after the address which 35 | * other parses will deal with. 36 | * ip [OUT] 37 | * The returned IP address, which also includes the version number and 38 | * prefix. If no prefix information (e.g. "/8") was included with the 39 | * address, then the prefix will be the length of the entire address 40 | * (32 bits for IPv4, 128 bits for IPv6). 41 | * @return 42 | * Returns 'true' if a valid address is found, and positions '*offset' to point 43 | * to the next character after the address. 44 | * Returns 'false' if a error occurs, and positions '*offset' to point to the 45 | * character at fault. 46 | */ 47 | int 48 | parse_ip_address(const char *px, unsigned *offset, size_t length, struct ParsedIpAddress *ip); 49 | 50 | void 51 | format_ip_address( char *buf, size_t sizeof_buf, 52 | const void *v_addr, unsigned version, 53 | unsigned prefix_length); 54 | 55 | void 56 | format_ipv6_address(char *buf, size_t sizeof_buf, const void *v_addr); 57 | 58 | /** 59 | * Does a quick unit test of the address parser. Returns '0' if everything is ok, and 60 | * some other number if there was a problem. 61 | */ 62 | unsigned 63 | parse_ip_selftest(); 64 | 65 | 66 | int parse_ipv4_address(const char *px, unsigned *offset, size_t length, struct ParsedIpAddress *ip); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | #endif 72 | -------------------------------------------------------------------------------- /src/util-keyword.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ****************************************************************************/ 3 | #ifndef KEYWORD_H 4 | #define KEYWORD_H 5 | 6 | struct Keyword 7 | { 8 | const char *str; 9 | unsigned length; 10 | }; 11 | 12 | struct Keyword keyword_next(const char *line, unsigned *r_offset, unsigned max); 13 | struct Keyword keyword_next_to_comma(const char *line, unsigned *r_offset, unsigned max); 14 | struct Keyword keyword_next_opt_name(const char *line, unsigned *r_offset, unsigned max); 15 | struct Keyword keyword_next_opt_value(const char *line, unsigned *r_offset, unsigned max); 16 | struct Keyword keyword_next_path_element(const char *line, unsigned *r_offset, unsigned max); 17 | 18 | int keyword_is_equal(const struct Keyword *lhs, const char *rhs); 19 | struct Keyword keyword_get_file_prefix(const char *filename, unsigned *r_offset, unsigned length); 20 | void keyword_append(char *p, unsigned *r_offset, unsigned max, struct Keyword element); 21 | 22 | void keyword_to_name_value(const struct Keyword *field, struct Keyword *name, struct Keyword *value); 23 | int keyword_to_unsigned(struct Keyword *key, unsigned *r_result); 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/util-ranges.h: -------------------------------------------------------------------------------- 1 | #ifndef RANGES_H 2 | #define RANGES_H 3 | #include 4 | 5 | typedef uint64_t IPV6ADDR; 6 | 7 | /** 8 | * A range of either IP addresses or ports 9 | */ 10 | struct Range 11 | { 12 | unsigned begin; 13 | unsigned end; /* inclusive */ 14 | }; 15 | struct RangeV6 16 | { 17 | uint64_t begin[2]; 18 | uint64_t end[2]; 19 | }; 20 | 21 | struct RangeList 22 | { 23 | struct Range *list; 24 | unsigned count; 25 | unsigned max; 26 | }; 27 | 28 | struct RangeListV6 29 | { 30 | struct Range6 *list; 31 | unsigned count; 32 | unsigned max; 33 | }; 34 | 35 | /** 36 | * Adds the given range to the task list. The given range can be a duplicate 37 | * or overlap with an existing range, which will get combined with existing 38 | * ranges. 39 | * @param task 40 | * A list of ranges of either IPv4 addresses or port numbers. 41 | * @param begin 42 | * The first address of the range that'll be added. 43 | * @param end 44 | * The last address (inclusive) of the range that'll be added. 45 | */ 46 | void 47 | rangelist_add_range(struct RangeList *task, unsigned begin, unsigned end); 48 | void 49 | rangelist_add_range_v6(struct RangeList *task, uint64_t begin[2], uint64_t end[2]); 50 | 51 | /** 52 | * Removes the given range from the target list. The input range doesn't 53 | * have to exist, or can partial overlap with existing ranges. 54 | * @param task 55 | * A list of ranges of either IPv4 addresses or port numbers. 56 | * @param begin 57 | * The first address of the range that'll be removed. 58 | * @param end 59 | * The last address of the range that'll be removed (inclusive). 60 | */ 61 | void 62 | rangelist_remove_range(struct RangeList *task, unsigned begin, unsigned end); 63 | void 64 | rangelist_remove_range_v6(struct RangeList *task, uint64_t begin[2], uint64_t end[2]); 65 | 66 | /** 67 | * Same as 'rangelist_remove_range()', except the input is a range 68 | * structure instead of a start/stop numbers. 69 | */ 70 | void 71 | rangelist_remove_range2(struct RangeList *task, struct Range range); 72 | 73 | /** 74 | * Returns 'true' is the indicated port or IP address is in one of the task 75 | * ranges. 76 | * @param task 77 | * A list of ranges of either IPv4 addresses or port numbers. 78 | * @param number 79 | * Either an IPv4 address or a TCP/UDP port number. 80 | * @return 81 | * 'true' if the ranges contain the item, or 'false' otherwise 82 | */ 83 | int 84 | rangelist_is_contains(const struct RangeList *task, unsigned number); 85 | int 86 | rangelist_is_contains_v6(const struct RangeList *task, uint64_t number[2]); 87 | 88 | 89 | /** 90 | * Remove things from the target list. The primary use of this is the 91 | * "exclude-file" containing a list of IP addresses that we should 92 | * not scan 93 | * @param targets 94 | * Our array of target IP address (or port) ranges that we'll be 95 | * scanning. 96 | * @param excludes 97 | * A list, probably read in from --excludefile, of things that we 98 | * should not be scanning, that will override anything we otherwise 99 | * try to scan. 100 | * @return 101 | * the total number of IP addresses or ports removed. 102 | */ 103 | uint64_t 104 | rangelist_exclude( struct RangeList *targets, 105 | const struct RangeList *excludes); 106 | 107 | uint64_t 108 | rangelist_exclude_v6( struct RangeListV6 *targets, 109 | const struct RangeListV6 *excludes); 110 | 111 | 112 | /** 113 | * Counts the total number of IP addresses or ports in the target list. This 114 | * iterates over all the ranges in the table, summing up the count within 115 | * each range. 116 | * @param targets 117 | * A list of IP address or port ranges. 118 | * @return 119 | * The total number of address or ports. 120 | */ 121 | uint64_t 122 | rangelist_count(const struct RangeList *targets); 123 | 124 | uint64_t 125 | rangelist_count_v6(const struct RangeListV6 *targets); 126 | 127 | /** 128 | * Given an index in a continous range of [0...count], pick a corresponding 129 | * number (IP address or port) from a list of non-continuous ranges (not 130 | * necessarily starting from 0). In other words, given the two ranges 131 | * 10-19 50-69 132 | * we'll have a total of 30 possible numbers. Thus, the index goes from 133 | * [0..29], with the values 0..9 picking the corresponding values from the 134 | * first range, and the values 10..29 picking the corresponding values 135 | * from the second range. 136 | * 137 | * NOTE: This is a fundamental part of this program's design, that the user 138 | * can specify non-contiguous IP and port ranges, but yet we iterate over 139 | * them using a monotonicly increasing index variable. 140 | * 141 | * @param targets 142 | * A list of IP address ranges, or a list of port ranges (one or the 143 | * other, but not both). 144 | * @param index 145 | * An integer starting at 0 up to (but not including) the value returned 146 | * by 'rangelist_count()' for this target list. 147 | * @return 148 | * an IP address or port corresponding to this index. 149 | */ 150 | unsigned rangelist_pick(const struct RangeList *targets, uint64_t i); 151 | IPV6ADDR rangelist_pick_v6(const struct RangeListV6 *targets, uint64_t i); 152 | 153 | 154 | 155 | 156 | /** 157 | * Remove all the ranges in the range list. 158 | */ 159 | void 160 | rangelist_remove_all(struct RangeList *list); 161 | void 162 | rangelist_remove_all_v6(struct RangeList *list); 163 | 164 | 165 | 166 | /** 167 | * Does a regression test of this module 168 | * @return 169 | * 0 if the regression test succeeds, or a positive value on failure 170 | */ 171 | int 172 | ranges_selftest(void); 173 | 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /src/util-realloc2.c: -------------------------------------------------------------------------------- 1 | #include "util-realloc2.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define HALF (1UL << (sizeof(size_t) * 4)) 8 | 9 | void * 10 | REALLOC2(void *buf, size_t size, size_t count) 11 | { 12 | void *buf2; 13 | 14 | if (size == 0 || count == 0) { 15 | free(buf); 16 | return NULL; 17 | } 18 | 19 | /* Check for overflow. First, check if both integers are small, which is 20 | * cheap on CPUs. Second, if a potential overflow exists, the check 21 | * using integer-division, which is expensive on CPUs. The expensive operation 22 | * will happen for allocations larger than 64k on 32bit processors, 23 | * and allocations larger than 4-gigabytes on 64bit processors */ 24 | if (size >= HALF || count >= HALF) { 25 | if (count > SIZE_MAX / size) 26 | exit(1); 27 | } 28 | 29 | if (buf == NULL) 30 | buf2 = malloc(size * count); 31 | else 32 | buf2 = realloc(buf, size * count); 33 | 34 | if (buf2 == NULL) 35 | exit(1); 36 | 37 | return buf2; 38 | } 39 | 40 | 41 | char * 42 | STRDUP2(const char *str) 43 | { 44 | char *result; 45 | size_t len = strlen(str) + 1; 46 | 47 | result = MALLOC2(len); 48 | memcpy(result, str, len); 49 | 50 | return result; 51 | } 52 | -------------------------------------------------------------------------------- /src/util-realloc2.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_REALLOC2_H 2 | #define UTIL_REALLOC2_H 3 | #include 4 | 5 | void * 6 | REALLOC2(void *buf, size_t size, size_t count); 7 | 8 | char * 9 | STRDUP2(const char *str); 10 | 11 | #define MALLOC2(size) REALLOC2(0, 1, (size)) 12 | 13 | #endif -------------------------------------------------------------------------------- /src/zonefile-dfa.c: -------------------------------------------------------------------------------- 1 | #include "zonefile-dfa.h" 2 | #include 3 | 4 | 5 | 6 | void mydfa_init(struct MyDFA *dfa) 7 | { 8 | memset(dfa, 0, sizeof(*dfa)); 9 | 10 | memset(dfa->char_to_symbol, MAX_DFA_SYMBOLS-1, 256); 11 | memset(dfa->symbol_to_char, '*', 256); 12 | memset(dfa->table, 0xFF, sizeof(dfa->table)); 13 | dfa->accept_start = 0xFF; 14 | dfa->accepts[255 - dfa->accept_start] = 0xFFFFFFFF; 15 | 16 | /* Create symbol for unknown character */ 17 | 18 | /* Create symbols for spaces */ 19 | dfa->symbol_to_char[0] = ' '; 20 | dfa->char_to_symbol[' '] = 0; 21 | dfa->char_to_symbol['\t'] = 0; 22 | dfa->char_to_symbol['\r'] = 0; 23 | 24 | dfa->symbol_to_char[1] = '\n'; 25 | dfa->char_to_symbol['\n'] = 1; 26 | 27 | dfa->symbol_to_char[2] = '('; 28 | dfa->char_to_symbol['('] = 2; 29 | 30 | dfa->symbol_to_char[3] = ')'; 31 | dfa->char_to_symbol[')'] = 3; 32 | 33 | 34 | dfa->symbol_count = 4; 35 | 36 | /* Create initial space transitions */ 37 | dfa->table[0][0] = 0; 38 | 39 | /* Create accept state for parentheses */ 40 | { 41 | unsigned accept_state = --dfa->accept_start; 42 | dfa->accepts[0xFF - accept_state] = 0; 43 | dfa->table[0][dfa->char_to_symbol[')']] = (dfa_t)accept_state; 44 | dfa->table[0][dfa->char_to_symbol['(']] = (dfa_t)accept_state; 45 | } 46 | } 47 | 48 | void mydfa_add_symbols(struct MyDFA *dfa, const unsigned char *str, unsigned length) 49 | { 50 | unsigned i; 51 | 52 | for (i=0; ichar_to_symbol[c] == MAX_DFA_SYMBOLS-1) { 61 | dfa->char_to_symbol[c] = (unsigned char)dfa->symbol_count; 62 | dfa->char_to_symbol[c2] = (unsigned char)dfa->symbol_count; 63 | dfa->symbol_to_char[dfa->symbol_count] = c; 64 | dfa->symbol_count++; 65 | } 66 | } 67 | } 68 | 69 | 70 | void mydfa_add_pattern(struct MyDFA *dfa, const unsigned char *str, unsigned length, unsigned id) 71 | { 72 | unsigned state = 0; 73 | unsigned i; 74 | unsigned char c; 75 | unsigned char symbol; 76 | unsigned accept_state = --dfa->accept_start; 77 | 78 | /* Figure out "accept state */ 79 | dfa->accepts[0xFF - accept_state] = id; 80 | 81 | /* Add all the real characters */ 82 | for (i=0; ichar_to_symbol[c]; 85 | 86 | if (dfa->table[state][symbol] == 0xFF) { 87 | dfa->table[state][symbol] = (unsigned char)++dfa->state_count; 88 | } 89 | state = dfa->table[state][symbol]; 90 | } 91 | 92 | /* Add a transition for newline */ 93 | c = '\n'; 94 | symbol = dfa->char_to_symbol[c]; 95 | dfa->table[state][symbol] = (unsigned char)accept_state; 96 | 97 | /* Add the "space" transitions */ 98 | c = ' '; 99 | symbol = dfa->char_to_symbol[c]; 100 | if (dfa->table[state][symbol] == 0xFF) { 101 | dfa->table[state][symbol] = (unsigned char)++dfa->state_count; 102 | state = dfa->table[state][symbol]; 103 | for (i=0; itable[state][i] = (unsigned char)accept_state; 105 | dfa->table[state][0] = (unsigned char)state; 106 | } 107 | 108 | } 109 | 110 | 111 | unsigned mydfa_search(struct MyDFA *dfa, unsigned *in_state, const void *in_buf, unsigned *offset, unsigned length) 112 | { 113 | const unsigned char *buf = (const unsigned char *)in_buf; 114 | unsigned i = *offset; 115 | unsigned state = *in_state; 116 | unsigned accept_start = dfa->accept_start; 117 | SMALL_DFA_TABLE *table = &dfa->table; 118 | const unsigned char *char_to_symbol = dfa->char_to_symbol; 119 | 120 | 121 | while (i= accept_start) 124 | break; 125 | i++; 126 | } 127 | 128 | *in_state = state; 129 | *offset = i; 130 | if (state >= accept_start) 131 | return dfa->accepts[(255 - state) & 0xFF]; 132 | else 133 | return 0; 134 | } 135 | 136 | 137 | unsigned 138 | mydfa_selftest(struct MyDFA *dfa, const void *buf, unsigned expected_id) 139 | { 140 | unsigned state = 0; 141 | unsigned offset = 0; 142 | unsigned x; 143 | unsigned buf_length = (unsigned)strlen((const char *)buf); 144 | 145 | x = mydfa_search(dfa, &state, buf, &offset, buf_length); 146 | if (x == 0) 147 | return expected_id == 0; 148 | else 149 | return x == expected_id; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /src/zonefile-dfa.h: -------------------------------------------------------------------------------- 1 | #ifndef ZONE_DFA_H 2 | #define ZONE_DFA_H 3 | 4 | #define MAX_DFA_SYMBOLS 32 5 | typedef unsigned char dfa_t; 6 | typedef dfa_t SMALL_DFA_TABLE[256][MAX_DFA_SYMBOLS]; 7 | 8 | 9 | struct MyDFA 10 | { 11 | unsigned char char_to_symbol[256]; 12 | unsigned char symbol_to_char[256]; 13 | unsigned symbol_count; 14 | unsigned state_count; 15 | unsigned accept_start; 16 | SMALL_DFA_TABLE table; 17 | unsigned accepts[64]; 18 | }; 19 | 20 | 21 | void mydfa_init(struct MyDFA *dfa); 22 | void mydfa_add_symbols(struct MyDFA *dfa, const unsigned char *str, unsigned length); 23 | void mydfa_add_pattern(struct MyDFA *dfa, const unsigned char *str, unsigned length, unsigned id); 24 | unsigned mydfa_search(struct MyDFA *dfa, unsigned *in_state, const void *in_buf, unsigned *offset, unsigned length); 25 | unsigned mydfa_selftest(struct MyDFA *dfa, const void *buf, unsigned expected_id); 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/zonefile-field-charstring.c: -------------------------------------------------------------------------------- 1 | #include "zonefile-fields.h" 2 | #include 3 | 4 | 5 | /**************************************************************************** 6 | ****************************************************************************/ 7 | void 8 | mm_charstring_start(struct ZoneFileParser *parser) 9 | { 10 | parser->rr_buffer.length = 0; 11 | parser->rr_buffer.line_offset = 0; 12 | parser->rr_buffer.data = &parser->block->buf[parser->block->offset]; 13 | parser->s2 = 0; 14 | } 15 | 16 | /**************************************************************************** 17 | ****************************************************************************/ 18 | void 19 | mm_charstring_end(struct ZoneFileParser *parser) 20 | { 21 | unsigned length; 22 | unsigned start; 23 | 24 | /* Get offset to the first byte of the charstring, which will be 25 | * it's length field */ 26 | start = parser->rr_buffer.line_offset; 27 | 28 | /* Find the length of the charstring */ 29 | length = parser->rr_buffer.length - start - 1; 30 | 31 | /* Set the length field */ 32 | parser->rr_buffer.data[start] = (unsigned char)length; 33 | } 34 | 35 | /**************************************************************************** 36 | ****************************************************************************/ 37 | void 38 | mm_charstring_parse( 39 | struct ZoneFileParser *parser, 40 | const unsigned char *buf, 41 | unsigned *offset, 42 | unsigned length) 43 | { 44 | struct ParseBuffer *buffer = &parser->rr_buffer; 45 | unsigned i; 46 | unsigned s = parser->s2; 47 | const unsigned is_whitespace_allowed = 0; 48 | 49 | 50 | enum { 51 | $START = 0, 52 | $END = 1, 53 | $COMMENT = 2, 54 | $PARSE_ERROR = 3, 55 | 56 | $TEXT, 57 | $TEXT_ESC, 58 | $QUOTED, 59 | $QUOTED_ESC0, 60 | $QUOTED_ESC1, 61 | $QUOTED_ESC2, 62 | }; 63 | 64 | for (i=*offset; iline_offset = buffer->length++; 79 | 80 | if (c == '\"') { 81 | parser->is_string = 1; 82 | s = $QUOTED; 83 | continue; 84 | } else { 85 | parser->is_string = 0; 86 | s = $TEXT; 87 | } 88 | 89 | case $TEXT: 90 | switch (c) { 91 | case ' ': 92 | case '\t': 93 | case '\r': 94 | if (is_whitespace_allowed) 95 | continue; 96 | else { 97 | s = $END; 98 | continue; 99 | } 100 | case '\n': 101 | if (parser->is_multiline) { 102 | parser->src.line_number++; 103 | continue; 104 | } else { 105 | goto end; 106 | } 107 | case '(': 108 | parser->is_multiline = 1; 109 | continue; 110 | case ')': 111 | parser->is_multiline = 0; 112 | continue; 113 | default: 114 | if (buffer->length < (65536-12)) 115 | buffer->data[buffer->length++] = c; 116 | } 117 | continue; 118 | 119 | 120 | case $QUOTED: 121 | switch (c) { 122 | case '\"': 123 | s = $END; 124 | continue; 125 | case '\\': 126 | s = $QUOTED_ESC0; 127 | continue; 128 | case '\n': 129 | parser->src.line_number++; 130 | parse_err(parser, "TXT: unhandled condition\n"); 131 | 132 | default: 133 | if (buffer->length < (65536-12)) 134 | buffer->data[buffer->length++] = c; 135 | } 136 | continue; 137 | 138 | case $COMMENT: 139 | while (i < length && buf[i] != '\n') 140 | i++; 141 | if (i < length) { 142 | if (parser->is_multiline) { 143 | s = $END; 144 | continue; 145 | } 146 | goto end; 147 | } 148 | 149 | break; 150 | case $QUOTED_ESC0: 151 | if ('0' <= c && c <= '9') { 152 | parser->substring_esc = c - '0'; 153 | s = $QUOTED_ESC1; 154 | continue; 155 | } else { 156 | if (buffer->length < (65536-12)) 157 | buffer->data[buffer->length++] = '\\'; 158 | if (buffer->length < (65536-12)) 159 | buffer->data[buffer->length++] = c; 160 | s = $QUOTED; 161 | continue; 162 | } 163 | break; 164 | case $QUOTED_ESC1: 165 | if ('0' <= c && c <= '9') { 166 | parser->substring_esc *= 10; 167 | parser->substring_esc = c - '0'; 168 | s = $QUOTED_ESC2; 169 | continue; 170 | } else { 171 | if (buffer->length < (65536-12)) 172 | buffer->data[buffer->length++] = (unsigned char)parser->substring_esc; 173 | if (buffer->length < (65536-12)) 174 | buffer->data[buffer->length++] = c; 175 | s = $QUOTED; 176 | continue; 177 | } 178 | break; 179 | case $QUOTED_ESC2: 180 | if ('0' <= c && c <= '9') { 181 | parser->substring_esc *= 10; 182 | parser->substring_esc = c - '0'; 183 | if (buffer->length < (65536-12)) 184 | buffer->data[buffer->length++] = (unsigned char)parser->substring_esc; 185 | s = $QUOTED; 186 | continue; 187 | } else { 188 | if (buffer->length < (65536-12)) 189 | buffer->data[buffer->length++] = (unsigned char)parser->substring_esc; 190 | if (buffer->length < (65536-12)) 191 | buffer->data[buffer->length++] = c; 192 | s = $QUOTED; 193 | continue; 194 | } 195 | break; 196 | 197 | case $END: 198 | switch (c) { 199 | case ';': 200 | s = $COMMENT; 201 | continue; 202 | case ' ': 203 | case '\t': 204 | case '\r': 205 | continue; 206 | case '\n': 207 | if (parser->is_multiline) { 208 | parser->src.line_number++; 209 | continue; 210 | } else 211 | goto end; 212 | case ')': 213 | if (parser->is_multiline) { 214 | parser->is_multiline = 0; 215 | continue; 216 | } else { 217 | goto end; 218 | } 219 | case '(': 220 | if (parser->is_multiline) { 221 | goto end; 222 | } else { 223 | parser->is_multiline = 1; 224 | continue; 225 | } 226 | default: 227 | goto end; 228 | } 229 | 230 | 231 | case $PARSE_ERROR: 232 | while (is2 = s; 242 | *offset = i; 243 | } 244 | -------------------------------------------------------------------------------- /src/zonefile-fields.h: -------------------------------------------------------------------------------- 1 | /* 2 | For parsing individual fields within zone files 3 | */ 4 | #ifndef ZONE_FIELDS_H 5 | #define ZONE_FIELDS_H 6 | #include "zonefile-rr.h" 7 | #include "zonefile-insertion.h" 8 | #include "source.h" 9 | #include "zonefile-parse.h" 10 | 11 | struct ParseBuffer 12 | { 13 | unsigned length; 14 | unsigned line_offset; 15 | unsigned char *data; 16 | }; 17 | 18 | struct DomainBuilder 19 | { 20 | unsigned char length; 21 | unsigned char is_absolute; 22 | unsigned char label; 23 | unsigned char *name; 24 | }; 25 | 26 | struct rte_ring; 27 | 28 | /**************************************************************************** 29 | ****************************************************************************/ 30 | struct ZoneFileParser 31 | { 32 | unsigned s; 33 | unsigned s2; 34 | unsigned substring_esc; 35 | unsigned is_singlestep:1; 36 | unsigned is_multiline:1; 37 | unsigned is_commenting:1; 38 | unsigned is_string:1; 39 | 40 | uint64_t filesize; 41 | struct MyDFA *type_dfa; 42 | struct MyDFA *variable_dfa; 43 | 44 | uint64_t rr_number; 45 | struct DomainBuilder rr_domain; 46 | struct ParseBuffer rr_buffer; 47 | struct { 48 | unsigned count; 49 | unsigned short list[64]; 50 | } rr_typelist; 51 | struct { 52 | unsigned length; 53 | unsigned ellision; 54 | unsigned val; 55 | } rr_ipv6; 56 | struct { 57 | unsigned number; 58 | unsigned longitude; 59 | unsigned latitude; 60 | unsigned altitude; 61 | unsigned size; 62 | unsigned horiz_pre; 63 | unsigned vert_pre; 64 | unsigned char field; 65 | unsigned char digits; 66 | unsigned is_negative:1; 67 | } rr_location; 68 | struct { 69 | uint64_t result; 70 | unsigned count; 71 | } rr_base64; 72 | struct { 73 | uint64_t result; 74 | unsigned count; 75 | } rr_base32hex; 76 | struct { 77 | uint64_t result; 78 | unsigned count; 79 | } rr_hex; 80 | struct { 81 | uint64_t result; 82 | } rr_type; 83 | struct { 84 | unsigned result; 85 | unsigned count; 86 | unsigned intermediate; 87 | } rr_ipv4; 88 | 89 | 90 | 91 | struct InputSource src; 92 | 93 | /* 94 | * Insertion stuff 95 | */ 96 | RESOURCE_RECORD_CALLBACK callback; 97 | void *callbackdata; 98 | struct ParsedBlock the_blocks[64]; /*IMPORTANT: count must be power of 2 */ 99 | struct ParsedBlock *block; 100 | struct rte_ring *insertion_queue; 101 | struct rte_ring *free_queue; 102 | unsigned additional_threads; 103 | volatile unsigned running_threads; 104 | volatile unsigned is_running; 105 | }; 106 | struct Bytes; 107 | 108 | void x_parse_ipv4(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length); 109 | void x_parse_ipv6(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length, unsigned char *ipv6); 110 | void x_parse_txt(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length); 111 | void x_parse_base32hex(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length); 112 | void x_parse_base64(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length); 113 | void x_parse_ttl(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length); 114 | void x_parse_hex(struct ZoneFileParser *parser, const unsigned char *buf, unsigned *offset, unsigned length, unsigned is_whitespace_allowed); 115 | 116 | void parse_err(struct ZoneFileParser *parser, const char *fmt, ...); 117 | 118 | void mm_location_start(struct ZoneFileParser *parser); 119 | void mm_location_end(struct ZoneFileParser *parser); 120 | void mm_location_parse(struct ZoneFileParser *parser, 121 | const unsigned char *buf, unsigned *offset, unsigned length); 122 | 123 | 124 | 125 | extern char CONTROLCHAR[257]; 126 | 127 | unsigned 128 | parse_default2( struct ZoneFileParser *parser, 129 | const unsigned char *buf, unsigned *offset, unsigned *length, 130 | unsigned char *c); 131 | 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /src/zonefile-insertion.h: -------------------------------------------------------------------------------- 1 | #ifndef ZONEFILE_BLOCK_H 2 | #define ZONEFILE_BLOCK_H 3 | #include 4 | #include "domainname.h" 5 | struct ZoneFileParser; 6 | 7 | 8 | /**************************************************************************** 9 | * A "block" contains many parsed records from a zone file. This will be 10 | * handed off to a separate thread that will then insert them into 11 | ****************************************************************************/ 12 | struct ParsedBlock 13 | { 14 | /* The "origin" domain name. Whenever the origin changes in a zonefile 15 | * it forces the creation of a new block. Thus, the single origin 16 | * parameter can be considered valid for all records within a block. */ 17 | struct DomainPointer origin; 18 | unsigned char origin_buffer[256]; 19 | 20 | /* The last domain that was parsed, for when records start with spaces */ 21 | struct DomainPointer domain; 22 | unsigned char domain_buffer[256]; 23 | 24 | /* The current default TTL */ 25 | uint64_t ttl; 26 | 27 | /* A hint as to the filename, useful for printing error messages. This is 28 | * because 'parsing' the text of the file happens early, but insertion 29 | * of records into the catalog/database happens much later. If there is 30 | * an insertion error, we need to be able to tie it back to the file 31 | * the original record came from. For example, if entering two CNAMEs 32 | * for the same label produces an error on insertion into the database. 33 | */ 34 | char filename[256]; 35 | uint64_t filesize; 36 | 37 | /* The buffer containing parsed resource-records. We append onto this 38 | * buffer as we parse the file. Later, we hand the whole block over to 39 | * an insertion thread that pulls those records out and inserts them 40 | * into the database. */ 41 | unsigned char buf[256*1024]; 42 | unsigned offset; 43 | unsigned offset_start; 44 | }; 45 | 46 | 47 | /** 48 | * finish the old block of RR records and hand them off to a db-insertion 49 | * thread, and start a fresh block of records 50 | */ 51 | struct ParsedBlock * 52 | block_next_to_parse(struct ZoneFileParser *parser); 53 | 54 | void 55 | block_rr_finish(struct ParsedBlock *block); 56 | 57 | void 58 | block_rr_start(struct ParsedBlock *block); 59 | 60 | struct ParsedBlock * 61 | block_init(struct ZoneFileParser *parser, struct DomainPointer origin, uint64_t ttl); 62 | 63 | void 64 | block_end(struct ZoneFileParser *parser); 65 | 66 | void 67 | block_flush(struct ZoneFileParser *parser); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/zonefile-load.c: -------------------------------------------------------------------------------- 1 | #include "db.h" 2 | #include "db-zone.h" 3 | #include "zonefile-load.h" 4 | #include 5 | 6 | /****************************************************************************** 7 | ******************************************************************************/ 8 | static void 9 | format_domain(char *dst, size_t sizeof_dst, 10 | struct DomainPointer domain, 11 | struct DomainPointer origin) 12 | { 13 | unsigned i; 14 | unsigned d = 0; 15 | 16 | for (i=0; i 7 | #include 8 | #include 9 | #include "source.h" 10 | #include "domainname.h" 11 | #include "success-failure.h" 12 | 13 | 14 | enum { 15 | CLASS_ERROR, 16 | CLASS_IN, /* Internet */ 17 | CLASS_CS, /* CSNET (Obsolete) */ 18 | CLASS_CH, /* Chaos (used for version strings) */ 19 | CLASS_HS, /* Hesiod (Obsolete) */ 20 | }; 21 | 22 | 23 | const char * name_of_type(unsigned type); 24 | 25 | 26 | 27 | typedef enum SuccessFailure (*RESOURCE_RECORD_CALLBACK)( 28 | struct DomainPointer domain, 29 | struct DomainPointer origin, 30 | unsigned type, 31 | unsigned ttl, 32 | unsigned rdlength, 33 | const unsigned char *rdata, 34 | uint64_t filesize, 35 | void *userdata, 36 | const char *filename, 37 | unsigned line_number); 38 | 39 | /** 40 | * Call this before parsing a zone-file . 41 | * @param origin 42 | * The DNS "origin" of the zone, such as "." or ".com." or 43 | * ".example.net.". Normally empty, unless this is being 44 | * called to recursively parse files, in which case this 45 | * will be the current origin of the parent file. 46 | * @param ttl 47 | * The default Time-To-Live, which is normally just 0, unless 48 | * being recursively called, in which case this will be the 49 | * current TTL of the parent file 50 | * @param filesize 51 | * This is a hint for pre-allocating the data structures of a zone. 52 | * This assumes a file containing information as dense as the 53 | * .com zonefile, and does it's calculations from there. 54 | * @param filename 55 | * The name of the file being parsed. This is only used for printing 56 | * diagnostic information -- it's not used to open/close files. 57 | * @param callback 58 | * This function will be called once we've parsed a resource record. 59 | * This is almost always the function "zonefile_load()", which will 60 | * insert the parsed record into the database. The only case when 61 | * it isn't is when we are just benchmarking the parser, in which 62 | * case this function just drops the record. 63 | * @param callbackdata 64 | * Opaque user data associated with the callback. This is almost 65 | * always the global catalog/db. 66 | * @param extra_threads 67 | * The number of extra insertion threads to spawn, 0 if not using 68 | * multi-threaded parsing. Inserting records into the database 69 | * is the slow part, so it's useful to have more than one thread 70 | * doing it. 71 | */ 72 | struct ZoneFileParser * 73 | zonefile_begin(struct DomainPointer origin, uint64_t ttl, 74 | uint64_t filesize, const char *filename, 75 | RESOURCE_RECORD_CALLBACK callback, void *callbackdata, 76 | unsigned extra_threads); 77 | void 78 | zonefile_begin_again( 79 | struct ZoneFileParser *parser, 80 | struct DomainPointer origin, uint64_t ttl, uint64_t filesize, 81 | const char *filename); 82 | 83 | /* Call this when done, check return code for success(1) or failure(0) */ 84 | int zonefile_end(struct ZoneFileParser *parser); 85 | 86 | /* Write any cached info into the catalog */ 87 | int zonefile_flush(struct ZoneFileParser *parser); 88 | 89 | /** 90 | * Insert resource-records immediately into the catalog/database instead 91 | * of as a batch. This is useful for debugging only, and shouldn't be used 92 | * otherwise 93 | */ 94 | void zonefile_set_singlestep(struct ZoneFileParser *parser); 95 | 96 | /* Parse a chunk of a zone-file */ 97 | void zonefile_parse( 98 | struct ZoneFileParser *parser, 99 | /*const char *filename, 100 | RESOURCE_RECORD_CALLBACK callback, 101 | void *userdata,*/ 102 | const unsigned char *buf, 103 | size_t buf_length); 104 | 105 | /** 106 | * Process-wide configuration for this module. Should be called by main() 107 | * right at startup. 108 | */ 109 | int zonefile_parser_init(); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif 114 | #endif 115 | -------------------------------------------------------------------------------- /src/zonefile-rr.c: -------------------------------------------------------------------------------- 1 | #include "zonefile-rr.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/zonefile-rr.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertdavidgraham/robdns/d76d2e6817ebefe240c667aecdc478d7e3fec586/src/zonefile-rr.h -------------------------------------------------------------------------------- /src/zonefile-tracker.h: -------------------------------------------------------------------------------- 1 | #ifndef ZONEFILE_TRACKER_H 2 | #define ZONEFILE_TRACKER_H 3 | 4 | struct Tracker 5 | { 6 | FILE *fp; 7 | const char *filename; 8 | unsigned line_number; 9 | unsigned offset; 10 | unsigned length; 11 | uint64_t bytes_read; 12 | uint64_t bytes_reported; 13 | uint64_t file_size; 14 | clock_t when_reported; 15 | }; 16 | 17 | void 18 | tracker_report(struct Tracker *tracker, size_t len); 19 | 20 | uint64_t 21 | tracker_get_filesize(struct Tracker *tracker, const char *filename); 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /vs10/.gitignore: -------------------------------------------------------------------------------- 1 | ipch 2 | rob 3 | robdns.suo 4 | robdns.sdf 5 | robdns.opensdf 6 | robdns.vcxproj.user 7 | tmp 8 | -------------------------------------------------------------------------------- /vs10/robdns.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "robdns", "robdns.vcxproj", "{C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Debug|Win32.Build.0 = Debug|Win32 16 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Debug|x64.ActiveCfg = Debug|x64 17 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Debug|x64.Build.0 = Debug|x64 18 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Release|Win32.ActiveCfg = Release|Win32 19 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Release|Win32.Build.0 = Release|Win32 20 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Release|x64.ActiveCfg = Release|x64 21 | {C41F4EA3-3D4E-41B1-BB5D-5E5ED191F32B}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /xcode4/robdns.xcodeproj/.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | project.xcworkspace 3 | 4 | --------------------------------------------------------------------------------