├── .gitignore ├── CHANGELOG ├── DEPENDENCIES ├── LICENSE ├── Makefile ├── README ├── TODO ├── VERSION ├── download.sh ├── hmac.c ├── hmac.h ├── libuinet.patch ├── range.c ├── range.h ├── route.c ├── route.h ├── scan.c ├── sha1.c ├── sha1.h ├── time.c ├── time.h ├── tls.h ├── utils.c ├── utils.h └── version.h /.gitignore: -------------------------------------------------------------------------------- 1 | libuinet 2 | netmap 3 | *.o 4 | pbscan 5 | core 6 | core.* 7 | .*.swp 8 | tags 9 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 0.13 2 | - fixed compilation issues by fixing issues caused by modern GCC 3 | warnings related to indentation issues 4 | - removed deprecated SSL functional call and replaced with right one 5 | - tested compiliation on current Debian 9.1/stretch system (Sept. 2017) 6 | 0.12 7 | - finished proper README documenting all options 8 | 9 | 0.11 10 | - keep track of active connections and display when killed due to timeout 11 | 12 | 0.10 13 | - added IP TTL, IP ID and TCP Window setting options 14 | 15 | 0.9 16 | - fixed x86 compilation issues by applying more patches to libuinet 17 | - fixed divide by zero if one specifies 0 bps for bandwidth limit 18 | - fixed long sleep issue when negative bandwidth limit specified 19 | - print TTL in verbose mode when receiving valid ACK 20 | - fixed race condition in initializing kicking off both threads 21 | 22 | 0.8 23 | - added -sC and -d option to enable scanning with custom payloads 24 | - added README 25 | 26 | 0.7 27 | - first public release 28 | -------------------------------------------------------------------------------- /DEPENDENCIES: -------------------------------------------------------------------------------- 1 | git 2 | libssl-dev 3 | libpcap-dev 4 | libc6-dev 5 | gcc 6 | make 7 | patch 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NETMAP_DIR=netmap 2 | UINET_DIST_DIR=libuinet 3 | UINET_DIR=libuinet/lib/libuinet 4 | UINET_ARCHIVE=$(UINET_DIR)/libuinet.a 5 | EV_DIR=libuinet/lib/libev 6 | EV_ARCHIVE=$(EV_DIR)/.libs/libev.a 7 | CFLAGS=-I/usr/include -I $(UINET_DIR)/api_include -Wall -Werror $(DEBUG_FLAGS) 8 | LFLAGS=-lpcap -lpthread -lcrypto -lm -lrt 9 | OBJECTS=utils.o range.o sha1.o hmac.o route.o time.o scan.o 10 | DISTFILES=CHANGELOG DEPENDENCIES README LICENSE VERSION TODO Makefile \ 11 | download.sh libuinet.patch 12 | VERSION=$(shell head -n1 VERSION) 13 | TARDIR=pbscan-$(VERSION) 14 | BIN=pbscan 15 | 16 | all: $(EV_ARCHIVE) $(UINET_ARCHIVE) $(BIN) 17 | 18 | debug: CFLAGS += -DDEBUG -g -ggdb 19 | debug: $(EV_ARCHIVE) $(UINET_ARCHIVE) $(BIN) 20 | 21 | libuinet: 22 | ./download.sh 23 | patch -d libuinet -p1 < libuinet.patch 24 | 25 | $(UINET_ARCHIVE): libuinet $(UINET_DIR)/uinet_api.c 26 | $(MAKE) -C $(UINET_DIR) NETMAP_INCLUDES=../../../netmap/sys 27 | 28 | $(EV_ARCHIVE): libuinet $(EV_DIR)/config.status 29 | $(MAKE) -C $(EV_DIR) 30 | 31 | $(EV_DIR)/config.status: 32 | cd $(EV_DIR) && ./configure --with-uinet=../../../$(UINET_DIR)/api_include 33 | 34 | $(BIN): $(OBJECTS) 35 | $(CC) $(OBJECTS) $(UINET_ARCHIVE) $(EV_ARCHIVE) $(LFLAGS) -o $@ 36 | strip $@ 37 | 38 | version.h: VERSION 39 | echo "const char * polarbearscan_version = \"$(VERSION)\";" > version.h 40 | 41 | scan.o: version.h scan.c 42 | $(CC) scan.c -c $(CFLAGS) -o $@ 43 | 44 | .c.o: 45 | $(CC) $< -c $(CFLAGS) -o $@ 46 | 47 | clean: 48 | $(RM) -r $(OBJECTS) $(BIN) 49 | $(MAKE) -C $(UINET_DIR) clean 50 | 51 | distclean: clean 52 | $(RM) -r $(UINET_DIST_DIR) $(NETMAP_DIR) tags 53 | 54 | tarball: 55 | mkdir /tmp/$(TARDIR) 56 | cp *.c *.h $(DISTFILES) /tmp/$(TARDIR) 57 | cd /tmp && tar zcf $(TARDIR).tar.gz $(TARDIR) && cd - && mv /tmp/$(TARDIR).tar.gz . 58 | rm -rf /tmp/$(TARDIR) 59 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | SUMMARY 2 | 3 | polarbearscan is an attempt to do faster and more efficient banner grabbing 4 | and port scanning. It combines two different ideas which hopefully will make 5 | it somewhat worthy of your attention and time. 6 | 7 | The first of these ideas is to use stateless SYN scanning using 8 | cryptographically protected cookies to parse incoming acknowledgements. To the 9 | best of the author's knowledge this technique was pioneered by Dan Kaminsky in 10 | scanrand. Scanrand was itself part of Paketto Keiretsu, a collection of 11 | scanning utilities, and it was released somewhere in 2001-2002. A mirror of 12 | this code can be found at Packet Storm [1]. 13 | 14 | The second idea is use a patched userland TCP/IP stack such that the scanner 15 | can restore state immediately upon receiving a cryptographically verified 16 | packet with both the SYN and ACK flags set. The userland stack being used here 17 | by polarbearscan is called libuinet [2]. Unlike some of the other userland 18 | TCP/IP stacks out there this one is very mature as it's simply a port of 19 | FreeBSD's TCP/IP stack. 20 | 21 | By patching the libuinet stack one can then construct a socket and complete 22 | the standard TCP 3-way handshake by replying with a proper ACK. Doing it this 23 | way a fully functional TCP connection is immediately established. This as 24 | opposed to other scanners (such as nmap) who would have to, after noting that 25 | a TCP port is open, now perform a full TCP connect via the kernel to do things 26 | such as banner grabbing or version scanning. A full TCP connect leads leads to 27 | a whole new TCP 3-way handshake being performed. This completely discards the 28 | implicit state which was built up by the initial two packets being exchanged 29 | between the hosts. By avoiding this one can reduce bandwidth usage and 30 | immediately go from detecting that a port is open to connecting to it. This 31 | connection can then simply sit back and receive data in banner grab mode or it 32 | could send out an HTTP request. 33 | 34 | Please note that the scanner right now only supports IPv4 based scanning and it 35 | will only work properly over Ethernet-type (wired or wireless) interfaces. 36 | There are no plans to support IPv6 or different interfaces in the near future. 37 | 38 | 39 | INSTALLATION 40 | 41 | Compiling the code is pretty straightforward. One just needs a working 42 | connection to the net and git needs to be installed such that the required 43 | dependencies can be downloaded. Besides that standard development utilities 44 | (gcc, make, patch), development editions of libraries (pthread, pcap, 45 | OpenSSL). On Debian based distributions one can simply install all the 46 | packages listed in the DEPENDENCIES file. After that one should be able to 47 | just type 'make' and the external dependencies will be checked out using git 48 | and the entire scanner will be build. This binary can then be copied to 49 | /usr/bin or /usr/local/bin or the like. 50 | 51 | If compilation fails please email the author (contact details below) and 52 | include the error output, kernel version, libc version and anything else that 53 | might help with reproducing and fixing the problem. Your help is kindly 54 | appreciated. 55 | 56 | 57 | USAGE 58 | 59 | Running the tool should be pretty straightforward. You will need root 60 | privileges. The -h option shows brief usage information and the options 61 | explained. In most cases one whould not need more than specifying the type of 62 | scan to perform, the port lists to scan and the target IP or IP-ranges. CIDR- 63 | noation is supported for the IP ranges. 64 | 65 | There are four different scan types which are specified with -s. 66 | 67 | -sB: This does a standard banner grab. The scanner will not send any data as 68 | it will simply wait and receive data and display it up until the first 69 | newline or carriage return received. 70 | 71 | -sH: This mode sends a "GET / HTTP/1.1" request to every successfully setup 72 | connection. It's very useful for quickly identifying HTTP servers. 73 | 74 | -sT: TLS scanning mode sends a TLS1.0 NULL probe with zero options and zero 75 | algorithms specified. However if there's a valid TLS server on the 76 | receiving end it will parse out and try to figure out if it's a valid 77 | TLS Error response which will then be dispalyed. 78 | 79 | -sC: Custom scanning wich will load a payload from a file (specified with -d) 80 | and send this payload out to every successfully established socket. Can 81 | be useful for quickly probing very specific protocols 82 | 83 | -p: The list of TCP ports to scan which can be a range of ports or 84 | single ports with ranges and single ports seperated by comma's. Some 85 | examples: -p22,80,8080-9000,143 will scan port 22,80,143 and the range of 86 | 8080 to 9000. 87 | 88 | -b : The bandwidth limit to apply for the outgoing probes. This does not 89 | apply to the data sent and received over the sockets so only to the actual 90 | SYN probes being sent out. Examples: -b300k, -b67m, -b500b would yield 91 | bandwidth limits of 300kbps, 76mbps and 500bps respectively. 92 | 93 | -d : Filename of the file containing the payload used to the custom 94 | scan. The entire file will be sent up until a maximum of 128kB which 95 | should be more than enough for most purposes. 96 | 97 | -t: This specifies the amount of seconds that the scanner will wait 98 | after it has sent out all the probes with receiving data back over the 99 | still connected sockets. That is assuming there are any otherwise it will 100 | bail out the moment there's no more work left to do. 101 | 102 | -x: This forces the tool to alwyas dump output received in hexadecimal 103 | notation. Otherwise it will only dump data in hexadecimal notation if 104 | non-printable characters are found. 105 | 106 | -v: This specifies some verbose output. It's mostly only useful for debugging. 107 | 108 | -i : The interface to use for selecting the source IP and setting up 109 | the pcap backend. This should not be necessary on standard machines with 110 | just one properly configured NIC but with multiple NICs one might need it. 111 | 112 | -r : The random seed to use for the RNG being used. Mostly useful for 113 | debugging and making sure that one can get the tool to generate the exact 114 | same sequence of packets again. The argument is an integer and can be 115 | specified in hexadecimal and decimal notation. 116 | 117 | -T : Override the default IP TTL value to use in SYN probes. Not really 118 | necessary for anything but included for the sake of completeness. 119 | 120 | -W : Override the default TCP Window size value to use in SYN probes. Not 121 | really necessary for anything but included for the sake of completeness. 122 | 123 | -I : Override the default IP ID value to use in SYN probes. Not really 124 | necessary for anything but included for the sake of completeness. 125 | 126 | -n: This option should only be used if you know what you're doing. It will 127 | make sure the tool does NOT set the firewall rule to drop all outgoing 128 | RST packets. If this is used then the scanner will not fork and one has 129 | the responsibility to set this rule by hand as otherwise the kernel will 130 | send RST packets back for every SYNACK packet received. This will make 131 | the tool simply not work. The rule as it's being set on Linux is the 132 | following: 133 | 134 | $ /sbin/iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 135 | 136 | -o: This option does not do the I/O redirection so one will see more output 137 | of the uinet internals. It's only added for the sake of completeness or 138 | for debugging scenario's as it's not very useful otherwise. 139 | 140 | -h: The usage information. 141 | 142 | Some examples on how to use the tool. To do a banner grab of port 22 on a /24 143 | range use like: 144 | 145 | ./pbscan -sB -p22 x.x.x.x/24 146 | 147 | To do an HTTP scan on several common HTTP ports for a single IP with the output 148 | in hexadecimal mode use: 149 | 150 | ./pbscan -sH -x -p80,8080-9000 x.x.x.x 151 | 152 | During scanning when you press a key on standard input you see some stats being 153 | printed out, such as the amount of open ports identified, the amount of valid 154 | TCP acks received the number of currently active connections, and how many SYN 155 | probes of the total have already been sent out. This will look something like: 156 | 157 | sent: 1.97% (of 254), open: 0, active: 2, acks: 2 158 | 159 | 160 | AUTHOR 161 | 162 | This tool was written by Vincent Berg. Contact me by emailing 163 | gvb@santarago.org or visit my website http://santarago.org for updated 164 | releases/news on this scanner. 165 | 166 | 167 | THANKS 168 | 169 | Much appreciation for several folks that helped out testing, porting this 170 | cool and reporting bugs. Thanks to Ehab, Joseph, Alejandro, Julian and Diego. 171 | 172 | 173 | REFERENCES 174 | 175 | [1] http://packetstormsecurity.com/files/30489/paketto-1.10.tar.gz.html 176 | 177 | [2] http://wanproxy.org/libuinet.shtml 178 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - FreeBSD port 2 | 3 | - add support for exclude IP's and IP ranges such that we 4 | can blacklist certain IP ranges when scanning 5 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.13 2 | -------------------------------------------------------------------------------- /download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ORIGPATH=$PWD 4 | NM="netmap" 5 | LU="libuinet" 6 | 7 | if [ ! -d $NM ]; then 8 | git clone https://github.com/luigirizzo/netmap 9 | cd $NM 10 | git checkout 32e06f9d18bf82e40a7c5b6e769c0ca7607913fc 11 | cd $ORIGPATH 12 | fi 13 | 14 | if [ ! -d $LU ]; then 15 | git clone https://github.com/pkelsey/libuinet.git 16 | cd $LU 17 | git checkout 0db87ba4a5b2113eb7cf529a3aa7170431a3bf4d 18 | cd $ORIGPATH 19 | fi 20 | -------------------------------------------------------------------------------- /hmac.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #include 21 | #include 22 | 23 | #include "sha1.h" 24 | 25 | #define BLOCKSIZE 64 /* SHA-1 blocksize */ 26 | 27 | void 28 | hmac(unsigned char * data, uint32_t datalen, unsigned char * key, 29 | uint32_t keylen, unsigned char hmac[20]) 30 | { 31 | SHA1_CTX ctx; 32 | unsigned char k_ipad[BLOCKSIZE], k_opad[BLOCKSIZE]; 33 | unsigned char digest[20]; /* SHA-1 digest is 20 bytes long */ 34 | int i; 35 | 36 | if (keylen > BLOCKSIZE) { 37 | SHA1Init(&ctx); 38 | SHA1Update(&ctx, key, keylen); 39 | SHA1Final(digest, &ctx); 40 | 41 | key = digest; 42 | keylen = sizeof(digest); 43 | } 44 | 45 | 46 | /* this ensures zero padding if keylen < blocksize */ 47 | memset(k_ipad, 0, sizeof(k_ipad)); 48 | memset(k_opad, 0, sizeof(k_opad)); 49 | memcpy(k_ipad, key, keylen); 50 | memcpy(k_opad, key, keylen); 51 | 52 | /* XOR key with ipad and opad values */ 53 | for (i=0;isa_len != sizeof (*sinp)) 119 | + return (EINVAL); 120 | + 121 | + if (sinp->sin_family == AF_INET 122 | + && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) 123 | + return (EAFNOSUPPORT); 124 | + 125 | + td = curthread; 126 | + 127 | + if (so->so_state & SS_ISCONNECTING) { 128 | + error = EALREADY; 129 | + return error; 130 | + } 131 | + CURVNET_SET(so->so_vnet); 132 | + 133 | + inp = sotoinpcb(so); 134 | + INP_WLOCK(inp); 135 | + 136 | + if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 137 | + error = EINVAL; 138 | + goto out; 139 | + } 140 | + tp = intotcpcb(inp); 141 | + 142 | + INP_HASH_WLOCK(&V_tcbinfo); 143 | + if (inp->inp_lport == 0) { 144 | + memset(&sin, 0, sizeof(sin)); 145 | + sin.sin_port = sport; 146 | + sin.sin_len = sizeof(struct sockaddr_in); 147 | + sin.sin_family = AF_INET; 148 | + error = in_pcbbind(inp, (struct sockaddr *)&sin, td->td_ucred); 149 | + if (error) { 150 | + goto out; 151 | + } 152 | + } 153 | + 154 | + /* 155 | + * Cannot simply call in_pcbconnect, because there might be an 156 | + * earlier incarnation of this same connection still in 157 | + * TIME_WAIT state, creating an ADDRINUSE error. 158 | + */ 159 | + laddr = inp->inp_laddr; 160 | + lport = inp->inp_lport; 161 | + error = in_pcbconnect_setup(inp, (struct sockaddr *)nam, &laddr.s_addr, &lport, 162 | + &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred); 163 | + if (error && oinp == NULL) { 164 | + printf("fuckyouasdfasdfasdf\n"); 165 | + goto out; 166 | + } 167 | + if (oinp) { 168 | + error = EADDRINUSE; 169 | + goto out; 170 | + } 171 | + inp->inp_laddr = laddr; 172 | + in_pcbrehash(inp); 173 | + INP_HASH_WUNLOCK(&V_tcbinfo); 174 | + 175 | + soisconnecting(so); 176 | + TCPSTAT_INC(tcps_connattempt); 177 | + tp->t_state = TCPS_SYN_SENT; 178 | + tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); 179 | + tp->iss = htonl(iss); 180 | + tcp_sendseqinit(tp); 181 | + 182 | + /* Advance due to sent SYN */ 183 | + tp->snd_max++; 184 | + tp->snd_nxt++; 185 | + 186 | +out: 187 | + INP_HASH_WUNLOCK(&V_tcbinfo); 188 | + INP_WUNLOCK(inp); 189 | + 190 | + CURVNET_RESTORE(); 191 | + 192 | + return (error); 193 | +} 194 | + 195 | +void * 196 | +uinet_if_get_pcap_handler(uinet_instance_t uinst, const char * ifname) 197 | +{ 198 | + struct uinet_if * uif; 199 | + 200 | + if (!ifname) return NULL; 201 | + CURVNET_SET(uinst->ui_vnet); 202 | + uif = uinet_iffind_byname(ifname); 203 | + CURVNET_RESTORE(); 204 | + if (!uif || uif->type != UINET_IFTYPE_PCAP) return NULL; 205 | + return if_pcap_get_pcap_handler(uif); 206 | +} 207 | + 208 | +int 209 | +uinet_if_set_pcap_handler(uinet_instance_t uinst, const char * ifname, void * handler) 210 | +{ 211 | + struct uinet_if * uif; 212 | 213 | + if (!ifname) return -1; 214 | + CURVNET_SET(uinst->ui_vnet); 215 | + uif = uinet_iffind_byname(ifname); 216 | + CURVNET_RESTORE(); 217 | + if (!uif || uif->type != UINET_IFTYPE_PCAP) return -1; 218 | + return if_pcap_set_pcap_handler(uif, handler); 219 | +} 220 | diff --git a/lib/libuinet/uinet_api.symlist b/lib/libuinet/uinet_api.symlist 221 | index f1b1cae..d9f566e 100644 222 | --- a/lib/libuinet/uinet_api.symlist 223 | +++ b/lib/libuinet/uinet_api.symlist 224 | @@ -90,3 +90,7 @@ uinet_if_xmit 225 | uinet_lock_log_set_file 226 | uinet_lock_log_enable 227 | uinet_lock_log_disable 228 | +uinet_fake_soconnect 229 | +uinet_if_get_pcap_handler 230 | +uinet_if_set_pcap_handler 231 | +uinet_iffind_byname 232 | diff --git a/lib/libuinet/uinet_config.c b/lib/libuinet/uinet_config.c 233 | index 5fbede0..d7a4045 100644 234 | --- a/lib/libuinet/uinet_config.c 235 | +++ b/lib/libuinet/uinet_config.c 236 | @@ -85,7 +85,7 @@ int 237 | uinet_ifcreate(uinet_instance_t uinst, uinet_iftype_t type, const char *configstr, 238 | const char *alias, unsigned int cdom, int cpu, uinet_if_t *uif) 239 | { 240 | - struct uinet_if *new_uif; 241 | + struct uinet_if *new_uif = NULL; 242 | int alias_len; 243 | int error = 0; 244 | 245 | diff --git a/lib/libuinet/uinet_host_interface.c b/lib/libuinet/uinet_host_interface.c 246 | index d095625..4ccf7d8 100644 247 | --- a/lib/libuinet/uinet_host_interface.c 248 | +++ b/lib/libuinet/uinet_host_interface.c 249 | @@ -1108,7 +1108,7 @@ uhi_arc4rand(void *ptr, unsigned int len, int reseed) 250 | 251 | /* XXX assuming that we don't have to manually seed this */ 252 | 253 | - RAND_pseudo_bytes(ptr, len); 254 | + RAND_bytes(ptr, len); 255 | #else 256 | if (reseed) 257 | arc4random_stir(); 258 | diff --git a/lib/libuinet/uinet_if_pcap.c b/lib/libuinet/uinet_if_pcap.c 259 | index 18bed04..1483329 100644 260 | --- a/lib/libuinet/uinet_if_pcap.c 261 | +++ b/lib/libuinet/uinet_if_pcap.c 262 | @@ -361,7 +361,6 @@ if_pcap_setup_interface(struct if_pcap_softc *sc) 263 | ether_ifattach(ifp, sc->addr); 264 | ifp->if_capabilities = ifp->if_capenable = IFCAP_HWSTATS; 265 | 266 | - 267 | mtx_init(&sc->tx_lock, "txlk", NULL, MTX_DEF); 268 | 269 | if (kthread_add(if_pcap_send, sc, NULL, &sc->tx_thread, 0, 0, "pcap_tx: %s", ifp->if_xname)) { 270 | @@ -402,3 +401,16 @@ if_pcap_detach(struct uinet_if *uif) 271 | } 272 | 273 | 274 | +void * 275 | +if_pcap_get_pcap_handler(struct uinet_if * uif) 276 | +{ 277 | + if (!uif || !(uif->ifdata)) return NULL; 278 | + return if_pcap_host_get_pcap_handler(((struct if_pcap_softc *)uif->ifdata)->pcap_host_ctx); 279 | +} 280 | + 281 | +int 282 | +if_pcap_set_pcap_handler(struct uinet_if * uif, void * handler) 283 | +{ 284 | + if (!uif || !(uif->ifdata)) return -1; 285 | + return if_pcap_host_set_pcap_handler(((struct if_pcap_softc *)uif->ifdata)->pcap_host_ctx, handler); 286 | +} 287 | diff --git a/lib/libuinet/uinet_if_pcap.h b/lib/libuinet/uinet_if_pcap.h 288 | index a7b84cb..a74f4f9 100644 289 | --- a/lib/libuinet/uinet_if_pcap.h 290 | +++ b/lib/libuinet/uinet_if_pcap.h 291 | @@ -28,5 +28,7 @@ 292 | 293 | int if_pcap_attach(struct uinet_if *uif); 294 | int if_pcap_detach(struct uinet_if *uif); 295 | +void * if_pcap_get_pcap_handler(struct uinet_if *uif); 296 | +int if_pcap_set_pcap_handler(struct uinet_if * uif, void * handler); 297 | 298 | #endif /* _UINET_IF_PCAP_H_ */ 299 | diff --git a/lib/libuinet/uinet_if_pcap_host.c b/lib/libuinet/uinet_if_pcap_host.c 300 | index 2224075..7dab625 100644 301 | --- a/lib/libuinet/uinet_if_pcap_host.c 302 | +++ b/lib/libuinet/uinet_if_pcap_host.c 303 | @@ -46,6 +46,7 @@ struct if_pcap_host_context { 304 | int isfile; 305 | const char *ifname; 306 | if_pcap_handler pkthandler; 307 | + pcap_handler if_pcap_packet_handler; 308 | void *pkthandlerarg; 309 | uint64_t last_packet_delivery; 310 | uint64_t last_packet_timestamp; 311 | @@ -139,10 +140,12 @@ if_pcap_sendpacket(struct if_pcap_host_context *ctx, const uint8_t *buf, unsigne 312 | static void 313 | if_pcap_packet_handler(struct if_pcap_host_context *ctx, const struct pcap_pkthdr *pkthdr, const unsigned char *pkt) 314 | { 315 | + pcap_handler pcap_h; 316 | uint64_t timestamp; 317 | uint64_t now; 318 | uint64_t time_since_last_delivery; 319 | uint64_t time_since_last_capture; 320 | + char reject = 0; 321 | 322 | if (ctx->isfile) { 323 | timestamp = (uint64_t)pkthdr->ts.tv_sec * 1000000000ULL + (uint64_t)pkthdr->ts.tv_usec * 1000; 324 | @@ -159,9 +162,30 @@ if_pcap_packet_handler(struct if_pcap_host_context *ctx, const struct pcap_pkthd 325 | ctx->last_packet_timestamp = timestamp; 326 | } 327 | 328 | - ctx->pkthandler(ctx->pkthandlerarg, pkt, pkthdr->caplen); 329 | + pcap_h = if_pcap_host_get_pcap_handler(ctx); 330 | + if (pcap_h) { 331 | + pcap_h((char *)&reject, pkthdr, pkt); 332 | + } 333 | + 334 | + if (!reject) { 335 | + ctx->pkthandler(ctx->pkthandlerarg, pkt, pkthdr->caplen); 336 | + } 337 | } 338 | 339 | +void * 340 | +if_pcap_host_get_pcap_handler(struct if_pcap_host_context * ctx) 341 | +{ 342 | + if (!ctx) return NULL; 343 | + return ctx->if_pcap_packet_handler; 344 | +} 345 | + 346 | +int 347 | +if_pcap_host_set_pcap_handler(struct if_pcap_host_context * ctx, void * handler) 348 | +{ 349 | + if (!ctx) return -1; 350 | + ctx->if_pcap_packet_handler = handler; 351 | + return 0; 352 | +} 353 | 354 | int 355 | if_pcap_loop(struct if_pcap_host_context *ctx) 356 | diff --git a/lib/libuinet/uinet_if_pcap_host.h b/lib/libuinet/uinet_if_pcap_host.h 357 | index 718150a..bc26a98 100644 358 | --- a/lib/libuinet/uinet_if_pcap_host.h 359 | +++ b/lib/libuinet/uinet_if_pcap_host.h 360 | @@ -34,5 +34,7 @@ struct if_pcap_host_context *if_pcap_create_handle(const char *ifname, unsigned 361 | void if_pcap_destroy_handle(struct if_pcap_host_context *ctx); 362 | int if_pcap_sendpacket(struct if_pcap_host_context *ctx, const uint8_t *buf, unsigned int size); 363 | int if_pcap_loop(struct if_pcap_host_context *ctx); 364 | +void * if_pcap_host_get_pcap_handler(struct if_pcap_host_context * ctx); 365 | +int if_pcap_host_set_pcap_handler(struct if_pcap_host_context * ctx, void * handler); 366 | 367 | #endif /* _UINET_IF_PCAP_HOST_H_ */ 368 | diff --git a/lib/libuinet/uinet_internal.h b/lib/libuinet/uinet_internal.h 369 | index bb139ba..0b5dd07 100644 370 | --- a/lib/libuinet/uinet_internal.h 371 | +++ b/lib/libuinet/uinet_internal.h 372 | @@ -30,7 +30,8 @@ 373 | #include 374 | 375 | #include 376 | -#include 377 | +//#include 378 | +struct vnet; 379 | 380 | #include "uinet_api.h" 381 | 382 | diff --git a/mk/kern.mk b/mk/kern.mk 383 | index bd87af6..5ecd0d5 100644 384 | --- a/mk/kern.mk 385 | +++ b/mk/kern.mk 386 | @@ -48,11 +48,6 @@ endif 387 | # cache tag lines). 388 | # 389 | ifeq (${MACHINE_CPUARCH},i386) 390 | -ifneq (${COMPILER_TYPE},clang) 391 | -CFLAGS+= -mno-align-long-strings -mpreferred-stack-boundary=2 392 | -else 393 | -CFLAGS+= 394 | -endif 395 | CFLAGS+= 396 | INLINE_LIMIT?= 8000 397 | endif 398 | diff --git a/mk/kern.pre.mk b/mk/kern.pre.mk 399 | index 882b629..46fc3da 100644 400 | --- a/mk/kern.pre.mk 401 | +++ b/mk/kern.pre.mk 402 | @@ -11,6 +11,10 @@ ifeq (${MACHINE_CPUARCH},x86_64) 403 | MACHINE_CPUARCH= amd64 404 | endif 405 | 406 | +ifeq (${MACHINE_CPUARCH},i686) 407 | +MACHINE_CPUARCH= i386 408 | +endif 409 | + 410 | AWK?= awk 411 | 412 | ifdef DEBUG 413 | @@ -113,6 +117,7 @@ IMACROS_FILTER+= __APPLE__ __MACH__ 414 | IMACROS_FILTER+= __CYGWIN__ __CYGWIN32__ 415 | IMACROS_FILTER+= __FreeBSD__ 416 | IMACROS_FILTER+= __linux __linux__ __gnu__linux__ linux 417 | +IMACROS_FILTER+= __STDC_VERSION__ 418 | IMACROS_FILTER+= _WIN32 _WIN64 419 | 420 | SPACE= $(eval) $(eval) 421 | diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h 422 | index 33190d8..eff9835 100644 423 | --- a/sys/i386/include/cpufunc.h 424 | +++ b/sys/i386/include/cpufunc.h 425 | @@ -89,6 +89,15 @@ bsrl(u_int mask) 426 | return (result); 427 | } 428 | 429 | +static __inline u_long 430 | +bsrq(u_long mask) 431 | +{ 432 | + u_long result; 433 | + 434 | + __asm ("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 435 | + return (result); 436 | +} 437 | + 438 | static __inline void 439 | clflush(u_long addr) 440 | { 441 | @@ -178,6 +187,14 @@ fls(int mask) 442 | return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 443 | } 444 | 445 | +#define HAVE_INLINE_FLSL 446 | + 447 | +static __inline int 448 | +flsl(long mask) 449 | +{ 450 | + return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); 451 | +} 452 | + 453 | #endif /* _KERNEL */ 454 | 455 | static __inline void 456 | diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src 457 | index cccf75a..42a3b06 100644 458 | --- a/sys/kern/vnode_if.src 459 | +++ b/sys/kern/vnode_if.src 460 | @@ -448,7 +448,7 @@ vop_advlockasync { 461 | IN int op; 462 | IN struct flock *fl; 463 | IN int flags; 464 | - IN struct task *task; 465 | + IN struct task *task; 466 | INOUT void **cookiep; 467 | }; 468 | 469 | diff --git a/lib/libuinet/uinet_if_bridge.c b/lib/libuinet/uinet_if_bridge.c 470 | index c2bdb5c..7b68deb 100644 471 | --- a/lib/libuinet/uinet_if_bridge.c 472 | +++ b/lib/libuinet/uinet_if_bridge.c 473 | @@ -200,7 +200,7 @@ if_bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 474 | if_bridge_init(sc); 475 | else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 476 | if_bridge_stop(sc); 477 | - break; 478 | + break; 479 | default: 480 | error = ether_ioctl(ifp, cmd, data); 481 | break; 482 | diff --git a/lib/libuinet/uinet_if_span.c b/lib/libuinet/uinet_if_span.c 483 | index 4b28237..771e534 100644 484 | --- a/lib/libuinet/uinet_if_span.c 485 | +++ b/lib/libuinet/uinet_if_span.c 486 | @@ -158,7 +158,7 @@ if_span_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 487 | if_span_init(sc); 488 | else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 489 | if_span_stop(sc); 490 | - break; 491 | + break; 492 | default: 493 | error = ether_ioctl(ifp, cmd, data); 494 | break; 495 | -------------------------------------------------------------------------------- /range.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "range.h" 26 | 27 | static inline int 28 | ip_parse(const char * input, uint32_t * res, size_t * resconsumed) 29 | { 30 | uint32_t ip1, ip2, ip3, ip4; 31 | size_t left, consumed; 32 | int ret; 33 | 34 | if (!input || !res) return -1; 35 | 36 | left = strlen(input); 37 | if (left > 255) return -1; /* input unreasonably long */ 38 | 39 | ret = sscanf(input, "%u.%u.%u.%u%zn", &ip1, &ip2, &ip3, &ip4, 40 | &consumed); 41 | if (ret != 4) return -1; 42 | if ((ip1 | ip2 | ip3 | ip4) & (~255)) return -1; 43 | 44 | /* leave IP in host order */ 45 | *res = (ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4; 46 | if (resconsumed) *resconsumed = consumed; 47 | 48 | return 0; 49 | } 50 | 51 | int 52 | iprange_parse(char * input, struct ip_range * res) 53 | { 54 | uint32_t ipstart, ipend, netmask, n; 55 | size_t consumed, left; 56 | int ret, i; 57 | 58 | if (!input || !res) return -1; 59 | 60 | consumed = 0; 61 | left = strlen(input); 62 | ret = ip_parse(input, &ipstart, &consumed); 63 | if (ret < 0) return -1; 64 | 65 | /* only single IP specified */ 66 | if (consumed == left) { 67 | res->start = ipstart; 68 | res->end = ipstart; 69 | return 0; 70 | } 71 | 72 | left -= (consumed + 1); 73 | input += consumed; 74 | 75 | if (*input == '-') { 76 | ret = ip_parse(++input, &ipend, &consumed); 77 | if (ret < 0) return -1; 78 | if (ipstart > ipend) { 79 | res->start = ipend; 80 | res->end = ipstart; 81 | } 82 | else { 83 | res->start = ipstart; 84 | res->end = ipend; 85 | } 86 | return 0; 87 | } 88 | else if (*input != '/') return -1; 89 | 90 | /* check if netmask is specified in bitmask notation /xx or in 91 | IP notation /x.x.x.x f.e. and parse accordingly */ 92 | ret = ip_parse(++input, &ipend, &consumed); 93 | if (!ret) { 94 | if (consumed != left) return -1; 95 | 96 | /* find ones following zeroes */ 97 | n = 0; 98 | for (i=0;i<32;i++) { 99 | if (!(ipend & (1 << (31-i)))) n=1; 100 | else if (n==1) return -1; 101 | } 102 | netmask = ipend; 103 | if (netmask == 0xffffffff) { 104 | res->start = res->end = ipstart; 105 | return 0; 106 | } 107 | } 108 | else { 109 | ret = sscanf(input, "%u%zn", &n, &consumed); 110 | if (ret != 1 || n < 1 || n > 32 || left != consumed) 111 | return -1; 112 | netmask = 0; 113 | for (i=0; istart = res->end = ipstart; 118 | return 0; 119 | } 120 | /* 121 | network: ipstart & netmask 122 | broadcast: ipstart | ~netmask 123 | */ 124 | } 125 | 126 | res->start = ((ipstart & netmask) | 0x1); 127 | res->end = ((ipstart | ~netmask) & ~0x1); 128 | 129 | if (res->start > res->end) { 130 | ipend = res->start; 131 | res->start = res->end; 132 | res->end = ipend; 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | void 139 | portrange_free(struct port_range * range) 140 | { 141 | struct port_range * next; 142 | if (!range) return; 143 | next = range->next; 144 | while (next) { 145 | next = next->next; 146 | free(range); 147 | } 148 | } 149 | 150 | int 151 | portrange_parse(char * input, struct port_range ** res) 152 | { 153 | struct port_range * first, * range = NULL; 154 | char * p; 155 | int current = 0, start = -1, end = -1; 156 | 157 | if (!input || !res) return -1; 158 | 159 | first = malloc(sizeof(struct port_range)); 160 | if (!first) return -1; 161 | first->next = NULL; 162 | 163 | range = first; 164 | p = input; 165 | while (*p) { 166 | current = 0; 167 | while (*p && *p >= '0' && *p <= '9') { 168 | current *= 10; 169 | current += (*p - '0'); 170 | p++; 171 | } 172 | if (current >= 65536) goto err; 173 | if (*p == ',') { 174 | if (start == -1) start = current; 175 | else if (end == -1) end = current; 176 | if (end > 0 && end < start) { 177 | goto err; 178 | } 179 | range->start = start; 180 | range->end = (end == -1 ? start : end); 181 | range->next = malloc(sizeof(struct port_range)); 182 | range = range->next; 183 | range->next = NULL; 184 | start = end = -1; 185 | } 186 | else if (*p == '-') { 187 | if (start == -1) start = current; 188 | } 189 | else if (!*p) { 190 | if (start == -1) start = current; 191 | if (end == -1) end = current; 192 | range->start = start; 193 | range->end = end; 194 | } 195 | p++; 196 | } 197 | 198 | /* empty string */ 199 | if (start == end && start == -1 && first == range) return -1; 200 | 201 | *res = first; 202 | return 0; 203 | err: 204 | if (range) portrange_free(range); 205 | return -1; 206 | } 207 | -------------------------------------------------------------------------------- /range.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #ifndef RANGE_H 21 | #define RANGE_H 22 | 23 | struct ip_range { 24 | uint32_t start; 25 | uint32_t end; 26 | }; 27 | 28 | struct port_range { 29 | struct port_range * next; 30 | uint16_t start; 31 | uint16_t end; 32 | }; 33 | 34 | int iprange_parse(char *, struct ip_range *); 35 | 36 | int portrange_parse(char *, struct port_range **); 37 | void portrange_free(struct port_range *); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /route.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | 21 | /* This is all a bit funky and simply ripped from the internals 22 | of the libuinet as tracing down the nest of includes needed 23 | to define the proper structures (rt_metrics and such) when 24 | including sys/net/route.h turned out to be too painful. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "uinet_api.h" 37 | #include "utils.h" 38 | 39 | #define ROUNDUP(a) \ 40 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 41 | 42 | struct rt_metrics { 43 | u_long rmx_locks; /* Kernel must leave these values alone */ 44 | u_long rmx_mtu; /* MTU for this path */ 45 | u_long rmx_hopcount; /* max hops expected */ 46 | u_long rmx_expire; /* lifetime for route, e.g. redirect */ 47 | u_long rmx_recvpipe; /* inbound delay-bandwidth product */ 48 | u_long rmx_sendpipe; /* outbound delay-bandwidth product */ 49 | u_long rmx_ssthresh; /* outbound gateway buffer limit */ 50 | u_long rmx_rtt; /* estimated round trip time */ 51 | u_long rmx_rttvar; /* estimated rtt variance */ 52 | u_long rmx_pksent; /* packets sent using this route */ 53 | u_long rmx_weight; /* route weight */ 54 | u_long rmx_filler[3]; /* will be used for T/TCP later */ 55 | }; 56 | 57 | struct rt_msghdr { 58 | u_short rtm_msglen; /* to skip over non-understood messages */ 59 | u_char rtm_version; /* future binary compatibility */ 60 | u_char rtm_type; /* message type */ 61 | u_short rtm_index; /* index for associated ifp */ 62 | int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ 63 | int rtm_addrs; /* bitmask identifying sockaddrs in msg */ 64 | pid_t rtm_pid; /* identify sender */ 65 | int rtm_seq; /* for sender to identify action */ 66 | int rtm_errno; /* why failed */ 67 | int rtm_fmask; /* bitmask used in RTM_CHANGE message */ 68 | u_long rtm_inits; /* which metrics we are initializing */ 69 | struct rt_metrics rtm_rmx; /* metrics themselves */ 70 | }; 71 | 72 | #define RTM_ADD 0x1 /* Add Route */ 73 | #define RTM_CHANGE 0x3 74 | 75 | #define RTM_VERSION 5 /* Up the ante and ignore older versions */ 76 | #define RTA_DST 0x1 /* destination sockaddr present */ 77 | #define RTA_GATEWAY 0x2 /* gateway sockaddr present */ 78 | #define RTA_NETMASK 0x4 /* netmask sockaddr present */ 79 | #define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ 80 | #define RTA_IFP 0x10 /* interface name sockaddr present */ 81 | #define RTA_IFA 0x20 /* interface addr sockaddr present */ 82 | #define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ 83 | #define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ 84 | 85 | #define RTF_GATEWAY 0x2 86 | 87 | extern int socket_write(struct uinet_socket *, void *, size_t); 88 | 89 | void 90 | route(const char * gw) 91 | { 92 | int ret; 93 | struct uinet_socket * so; 94 | struct rt_msghdr * rtm; 95 | struct uinet_sockaddr * sa; 96 | struct uinet_sockaddr_in * sin; 97 | char buf[4096]; 98 | 99 | errno = 0; 100 | ret = uinet_socreate(uinet_instance_default(), UINET_PF_ROUTE, &so, UINET_SOCK_RAW, 0); 101 | if (ret) { 102 | errno = ret; 103 | pfatal("uinet_socreate"); 104 | } 105 | 106 | memset(buf, 0, sizeof(buf)); 107 | 108 | rtm = (struct rt_msghdr *)buf; 109 | rtm->rtm_version = RTM_VERSION; 110 | rtm->rtm_type = RTM_ADD; 111 | rtm->rtm_flags = RTF_GATEWAY; 112 | rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 113 | rtm->rtm_pid = getpid(); 114 | rtm->rtm_seq = 1234; 115 | 116 | sa = (struct uinet_sockaddr *)(rtm + 1); 117 | sin = (struct uinet_sockaddr_in *)(sa); 118 | sin->sin_len = sizeof(struct uinet_sockaddr_in); 119 | sin->sin_family = AF_INET; 120 | sin->sin_addr.s_addr = inet_addr("0.0.0.0"); 121 | 122 | sa = (struct uinet_sockaddr *)((unsigned char *)(sa) + ROUNDUP(sa->sa_len)); 123 | sin = (struct uinet_sockaddr_in *)(sa); 124 | sin->sin_len = sizeof(struct uinet_sockaddr_in); 125 | sin->sin_family = AF_INET; 126 | sin->sin_addr.s_addr = inet_addr(gw); 127 | 128 | sa = (struct uinet_sockaddr *)((unsigned char *)(sa) + ROUNDUP(sa->sa_len)); 129 | sin = (struct uinet_sockaddr_in *)(sa); 130 | sin->sin_len = 0; 131 | sin->sin_family = AF_INET; 132 | 133 | sa = (struct uinet_sockaddr *)((unsigned char *)(sa) + ROUNDUP(sa->sa_len)); 134 | rtm->rtm_msglen = (char *)sa - buf; 135 | 136 | errno = socket_write(so, buf, rtm->rtm_msglen); 137 | if (errno) pfatal("socket_write"); 138 | 139 | /* probably should loop through reply messages and see whether 140 | the setting of the route succeeded; right now we just assume 141 | it worked. */ 142 | 143 | return; 144 | } 145 | -------------------------------------------------------------------------------- /route.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | 21 | #ifndef ROUTE_H 22 | #define ROUTE_H 23 | 24 | void route(const char * gw); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /scan.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #define __USE_BSD 1 34 | #define __FAVOR_BSD 1 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | 46 | /* uinet specific includes */ 47 | #include "uinet_api.h" 48 | #define EV_STANDALONE 1 49 | #define EV_UINET_ENABLE 1 50 | #include "libuinet/lib/libev/ev.h" 51 | 52 | /* local includes */ 53 | #include "utils.h" 54 | #include "range.h" 55 | #include "hmac.h" 56 | #include "route.h" 57 | #include "time.h" 58 | #include "tls.h" 59 | #include "version.h" 60 | 61 | /* system wide globals used for stdout/stderr redirection */ 62 | FILE * out = NULL; /* stdout file stream */ 63 | FILE * err = NULL; /* stderr file stream */ 64 | 65 | /* static globals used by the scanner */ 66 | static int raw_fd = -1; /* raw fd used to send raw packets */ 67 | static uint32_t rand_seed = 0; /* random seed */ 68 | static struct ip_range ip_range; /* range of IPs to scan */ 69 | static struct port_range * port_range; /* range of ports to scan */ 70 | static uint32_t src_ip; /* source IP in network order */ 71 | static uint32_t bcast_ip; /* broadcast IP in network order */ 72 | static uint32_t gw_ip; /* gateway IP in network order */ 73 | static uint32_t mask_ip; /* network mask in network order */ 74 | static double timeout; /* timeout in seconds */ 75 | static int quit = 0; /* shutting down if set to non-zero*/ 76 | static int scanner_done = 0; /* scanner done if set to non-zero */ 77 | static struct tai scanner_done_time; /* time that scanner was done */ 78 | static int force_hex_output = 0; /* force hexadecimal output */ 79 | static int verbose = 0; /* show verbose output */ 80 | static char scan_mode = 0; /* scan mode to use */ 81 | static char * gateway; /* IP addr of the gateway as string */ 82 | static struct ev_loop * loop; /* libev event loop reference */ 83 | static unsigned char * custom_data; /* data sent for custom scan */ 84 | static size_t custom_data_len; /* length of custom data */ 85 | static ev_timer scanner_break; /* timer to break out of event loop */ 86 | static useconds_t sleep_between_pkts; /* time to sleep between probes */ 87 | pthread_t threads[1]; /* thread references */ 88 | static uint16_t ip_id_value; /* IP ID value for the probes */ 89 | static uint8_t ip_ttl_value; /* IP TTL value for the probes */ 90 | static uint16_t tcp_win_value; /* TCP Window value for the probes */ 91 | 92 | 93 | /* stat counters */ 94 | static size_t total_syn_sent; 95 | static size_t total_syn_todo; 96 | static size_t total_ack_received; 97 | static size_t total_open_ports_found; 98 | static size_t total_active_connections; 99 | 100 | /* secret key data used in HMAC to detecting valid reply's to our probes */ 101 | #define SECRET_KEYSZ 8 /* must be multiple of 4 */ 102 | static unsigned char secret_key[SECRET_KEYSZ]; 103 | 104 | /* IP tables rule to set/unset dropping of TCP RST packets */ 105 | #define IPTABLES "/sbin/iptables" 106 | #define IPTABLES_ARG {IPTABLES, "-D", "OUTPUT", "-p", "tcp", \ 107 | "--tcp-flags", "RST", "RST", "-j", "DROP", NULL} 108 | 109 | /* HTTP probe used for HTTP scan mode */ 110 | #define HTTP_PROBE "GET / HTTP/1.0\r\n\r\n" 111 | #define HTTP_PROBE_LEN strlen(HTTP_PROBE) 112 | 113 | /* TLS1.0 probe used for SSL scan mode with zero timestamp and options */ 114 | #define SSL_PROBE "\x16\x03\x01\x00\x2c\x01\x00\x00\x28\x03\x01\x00" \ 115 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ 116 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ 117 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ 118 | "\x00" 119 | #define SSL_PROBE_LEN 49 120 | 121 | /* default ports; ftp,ssh,smtp,http,pop2,pop3,imap2,imap3,mysql,mssql */ 122 | #define DEFAULT_PORTRANGE "21,22,25,80,109,110,143,220,3306,1433" 123 | 124 | /* output macro's */ 125 | #define WARN(...) do { fprintf(out, "[!] "); fprintf(out, __VA_ARGS__); \ 126 | fprintf(out, "\n"); fflush(out); } while (0); 127 | #define OUT(...) do { fprintf(out, __VA_ARGS__); } while (0); 128 | #define VERBOSE(...) do { if (!verbose) break; fprintf(out, __VA_ARGS__); \ 129 | fflush(out); } while(0); 130 | 131 | /* used to calculate TCP/IP checksum */ 132 | struct pseudohdr { 133 | uint32_t src; 134 | uint32_t dst; 135 | uint8_t mbz; 136 | uint8_t proto; 137 | uint16_t len; 138 | }; 139 | 140 | /* holds callback state for the connections we're setting up */ 141 | struct connection { 142 | struct connection * next; 143 | struct connection * prev; 144 | ev_uinet watcher; 145 | struct uinet_socket * so; 146 | struct ev_uinet_ctx * soctx; 147 | struct tai ts; 148 | int counted; 149 | }; 150 | 151 | /* head of linked list */ 152 | static struct connection * first_connection = NULL; 153 | 154 | /* standard TCP/IP checksum routine */ 155 | static unsigned short 156 | csum(unsigned short * buf, size_t nwords) 157 | { 158 | unsigned long sum; 159 | 160 | for (sum=0; nwords > 0; nwords--) { 161 | sum += *buf++; 162 | } 163 | sum = (sum >> 16) + (sum & 0xffff); 164 | sum += (sum >> 16); 165 | return (unsigned short)(~sum); 166 | } 167 | 168 | /* 169 | * Calculates HMAC and truncates it to a 32-bit cookie with the input 170 | * consisting of the 4-tuple identifying the connection (src and destination 171 | * IPs and ports). 172 | */ 173 | static inline uint32_t 174 | calc_cookie(uint32_t src, uint32_t dst, uint16_t sport, uint16_t dport) 175 | { 176 | unsigned char buf[12], output[20]; 177 | 178 | memset(buf, 0, sizeof(buf)); 179 | *(uint32_t *)buf = src; 180 | *(uint32_t *)(&buf[4]) = dst; 181 | *(uint16_t *)(&buf[8]) = sport; 182 | *(uint16_t *)(&buf[10]) = dport; 183 | 184 | hmac(buf, sizeof(buf), secret_key, sizeof(secret_key), output); 185 | 186 | return *(uint32_t *)output; 187 | } 188 | 189 | /* 190 | * wrapper over the uinet UIO and IOV infrastructure so we can 191 | * simply supply a buffer and a length and get it written out to 192 | * the supplied socket 193 | */ 194 | int 195 | socket_write(struct uinet_socket * so, void * buf, size_t len) 196 | { 197 | struct uinet_uio uio; 198 | struct uinet_iovec iov; 199 | 200 | uio.uio_iov = &iov; 201 | iov.iov_base = buf; 202 | iov.iov_len = len; 203 | uio.uio_iovcnt = 1; 204 | uio.uio_offset = 0; 205 | uio.uio_resid = iov.iov_len; 206 | return uinet_sosend(so, NULL, &uio, 0); 207 | } 208 | 209 | /* 210 | * Send a TCP packet over the raw file descriptor pointed to by 'fd' with the 211 | * connection's 4-tuple identified by src/dst for the IP's and sport/dport 212 | * for the port numbers respectively. The TCP sequence and acknowledgement 213 | * numbers can also be supplied. Please note that all arguments are assumed 214 | * to already be in network byte order so no conversion in this function will 215 | * be done anymore. 216 | */ 217 | static void 218 | send_pkt(int fd, uint32_t src, uint32_t dst, uint16_t sport, uint16_t dport, 219 | uint32_t seq, uint32_t ack) 220 | { 221 | struct tcphdr * tcph; 222 | struct ip * iph; 223 | struct pseudohdr * psh; 224 | struct sockaddr_in sin; 225 | char buf[4096]; 226 | int ret; 227 | 228 | memset(buf, 0, sizeof(buf)); 229 | 230 | iph = (struct ip *)(buf); 231 | iph->ip_hl = 5; 232 | iph->ip_v = 4; 233 | iph->ip_tos = 0; 234 | iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); 235 | iph->ip_id = ip_id_value; 236 | iph->ip_off = 0; 237 | iph->ip_ttl = ip_ttl_value; 238 | iph->ip_p = IPPROTO_TCP; 239 | iph->ip_sum = 0; 240 | iph->ip_src.s_addr = src; 241 | iph->ip_dst.s_addr = dst; 242 | 243 | tcph = (struct tcphdr *)(buf + sizeof(struct ip)); 244 | tcph->th_sport = sport; 245 | tcph->th_dport = dport; 246 | tcph->th_seq = seq; 247 | tcph->th_ack = ack; 248 | tcph->th_off = 5; 249 | tcph->th_x2 = 0; 250 | tcph->th_flags = TH_SYN; 251 | tcph->th_win = tcp_win_value; 252 | tcph->th_sum = 0; 253 | tcph->th_urp = 0; 254 | 255 | psh = (struct pseudohdr *)(buf + sizeof(struct ip) + 256 | sizeof(struct tcphdr)); 257 | psh->src = iph->ip_src.s_addr; 258 | psh->dst = iph->ip_dst.s_addr; 259 | psh->mbz = 0; 260 | psh->proto = iph->ip_p; 261 | psh->len = ntohs(tcph->th_off << 2); 262 | 263 | tcph->th_sum = csum((unsigned short*)tcph, 264 | sizeof(struct tcphdr) + sizeof(struct pseudohdr)); 265 | 266 | sin.sin_family = AF_INET; 267 | sin.sin_port = tcph->th_dport; 268 | sin.sin_addr = iph->ip_dst; 269 | memset(&sin.sin_zero, 0, sizeof(sin.sin_zero)); 270 | 271 | ret = sendto(fd, buf, iph->ip_len, 0, (struct sockaddr *)&sin, 272 | sizeof(sin)); 273 | if ( ret < 0) pfatal("sendto"); 274 | } 275 | 276 | /* scanner thread */ 277 | static void * 278 | scanner(void * arg) 279 | { 280 | uint32_t i, j, seq, ack, dst_ip; 281 | uint16_t sport, dport; 282 | struct port_range * next; 283 | 284 | /* calculate total number of packets that have to be sent 285 | this number will be slightly 286 | */ 287 | next = port_range; 288 | while (next) { 289 | total_syn_todo += (next->end - next->start + 1); 290 | next = next->next; 291 | } 292 | total_syn_todo *= (ip_range.end-ip_range.start+1); 293 | 294 | /* correct the count for broadcast and network addresses if needed */ 295 | if (ntohl(bcast_ip) >= ip_range.end && ntohl(bcast_ip) 296 | <= ip_range.start) total_syn_todo--; 297 | if (ntohl((src_ip & mask_ip)) >= ip_range.end && 298 | ntohl((src_ip & mask_ip)) <= ip_range.end) total_syn_todo--; 299 | 300 | VERBOSE("total SYN probes to sent: %zu\n", total_syn_todo); 301 | 302 | /* loop over the IP range to scan and then for each IP loop over the 303 | port ranges that we want to scan */ 304 | for (i=ip_range.start; i<=ip_range.end; i++) { 305 | 306 | dst_ip = htonl(i); 307 | 308 | /* ignore broadcast IP or network mask IP */ 309 | if (dst_ip == bcast_ip || dst_ip == (src_ip & mask_ip)) { 310 | continue; 311 | } 312 | 313 | next = port_range; 314 | while (next) { 315 | for (j=next->start; j<=next->end; j++) { 316 | dport = htons(j); 317 | 318 | /* make sure source port is not privileged */ 319 | sport = htons(10000 + (rand_r(&rand_seed) 320 | % SHRT_MAX)); 321 | 322 | /* set random ACK value */ 323 | ack = htonl(rand_r(&rand_seed) % UINT_MAX); 324 | 325 | /* calculate cookie and set it as the 326 | sequence number */ 327 | seq = htonl(calc_cookie(src_ip, dst_ip, 328 | sport, dport)); 329 | 330 | /* send out the packet */ 331 | send_pkt(raw_fd, src_ip, dst_ip, 332 | sport, dport, seq, ack); 333 | 334 | total_syn_sent++; 335 | 336 | if (sleep_between_pkts) { 337 | usleep(sleep_between_pkts); 338 | } 339 | } 340 | next = next->next; 341 | } 342 | } 343 | 344 | /* signal that the scanner is done sending packets */ 345 | scanner_done = 1; 346 | tai_now(&scanner_done_time); 347 | 348 | pthread_exit(NULL); 349 | return 0; 350 | } 351 | 352 | inline static int 353 | min(int a, int b) { 354 | return (a < b ? a : b); 355 | } 356 | 357 | inline static void 358 | output_data(unsigned char * buf, size_t len) 359 | { 360 | unsigned char * p, * endp; 361 | size_t i, j; 362 | int dohex = 0; 363 | 364 | /* output in hex if that is a forced mode or if we only find 365 | printable characters and CR and LF (which we will strip out() */ 366 | endp = buf + len; 367 | p = buf; 368 | if (!force_hex_output) { 369 | while (p < endp) { 370 | if (!isprint(*p) && *p != '\r' && *p != '\n') 371 | break; 372 | p++; 373 | } 374 | dohex = (p != endp); 375 | } 376 | else dohex = 1; 377 | 378 | if (!dohex) { 379 | p = buf; 380 | while (p < endp) { 381 | if (*p == '\r' || *p == '\n') { 382 | *p = 0; 383 | break; 384 | } 385 | p++; 386 | } 387 | OUT("%s", buf); 388 | return; 389 | } 390 | 391 | /* try to parse a possible TLS response if in TLS scanning mode */ 392 | if (scan_mode == 'T' && !force_hex_output && len >= 7) { 393 | 394 | /* TLS fatal alert message received */ 395 | if (buf[0] == 0x15 && buf[1] == 0x3 && 396 | buf[3]==0x0 && buf[4]==0x2 && buf[5]==0x2) { 397 | OUT("TLSv1.%u alert received: (", buf[2]-1); 398 | 399 | for (i=0;ij) OUT(" "); 432 | OUT("%02x ", buf[i]); 433 | } 434 | OUT(" "); 435 | for(i=0;i<16-(len%16);i++) { 436 | if (i==7) OUT(" "); 437 | OUT(" "); 438 | } 439 | for(i=j;iso, 0); 458 | max_write = uinet_sowritable(w->so, 0); 459 | 460 | conn = w->data; 461 | 462 | /* If this connection wasn't counted yet count it now; counting 463 | is being done here to avoid duplicate connection counting 464 | as it's quite likely to get several ACKs for one probe if 465 | the userland stack hasn't had enough time to catch up yet. */ 466 | if (!conn->counted) { 467 | total_open_ports_found++; 468 | conn->counted = 1; 469 | } 470 | 471 | uinet_sogetconninfo(conn->so, &inc); 472 | tai_now(&now); 473 | 474 | memset(buffer, 0, sizeof(buffer)); 475 | 476 | if (scan_mode == 'B' || max_read != 0) 477 | OUT("%s:%u", uinet_inet_ntoa(inc.inc_ie.ie_faddr, addrbuf, 478 | sizeof(addrbuf)), ntohs(inc.inc_ie.ie_fport)); 479 | 480 | if (max_read == -1) { 481 | tai_now(&now); 482 | 483 | OUT(" (t/o: %zus)\n", (size_t)(now.x - conn->ts.x)); 484 | 485 | ev_uinet_stop(loop, &conn->watcher); 486 | uinet_soclose(conn->so); 487 | ev_uinet_detach(conn->soctx); 488 | total_active_connections--; 489 | 490 | if (conn->prev) conn->prev->next = conn->next; 491 | if (conn->next) conn->next->prev = conn->prev; 492 | if (conn == first_connection) first_connection = conn->prev; 493 | free(conn); 494 | 495 | return; 496 | } 497 | else if (max_read) { 498 | OUT(" -> "); 499 | read_size = min(min(max_read, max_write), sizeof(buffer)); 500 | 501 | uio.uio_iov = &iov; 502 | iov.iov_base = buffer; 503 | iov.iov_len = read_size; 504 | uio.uio_iovcnt = 1; 505 | uio.uio_offset = 0; 506 | uio.uio_resid = read_size; 507 | 508 | error = uinet_soreceive(w->so, NULL, &uio, NULL); 509 | if (0 != error) { 510 | OUT("(read error: %d, closing)\n", error); 511 | } 512 | else { 513 | if (iov.iov_len > sizeof(buffer)) 514 | iov.iov_len = sizeof(buffer); 515 | output_data(buffer, iov.iov_len); 516 | OUT("\n"); 517 | } 518 | ev_uinet_stop(loop, &conn->watcher); 519 | uinet_soclose(conn->so); 520 | ev_uinet_detach(conn->soctx); 521 | if (conn->prev) conn->prev->next = conn->next; 522 | if (conn->next) conn->next->prev = conn->prev; 523 | if (conn == first_connection) first_connection = conn->prev; 524 | free(conn); 525 | total_active_connections--; 526 | return; 527 | } 528 | 529 | error = 0; 530 | /* in banner scan mode we don't expect to get here */ 531 | if (scan_mode == 'B') { 532 | WARN("nothing to read; shouldnt happen\n"); 533 | return; 534 | } 535 | /* send HTTP scan probe */ 536 | else if (scan_mode == 'H') { 537 | error = socket_write(conn->so, HTTP_PROBE, HTTP_PROBE_LEN); 538 | } 539 | 540 | /* send SSL scan probe */ 541 | else if (scan_mode == 'T') { 542 | error = socket_write(conn->so, SSL_PROBE, SSL_PROBE_LEN); 543 | } 544 | 545 | /* send custom scan probe */ 546 | else if (scan_mode == 'C') { 547 | error = socket_write(conn->so, custom_data, custom_data_len); 548 | } 549 | 550 | if (error) { 551 | WARN("%s:%u (error when sending probe)\n", 552 | uinet_inet_ntoa(inc.inc_ie.ie_faddr, addrbuf, 553 | sizeof(addrbuf)), ntohs(inc.inc_ie.ie_fport)); 554 | } 555 | 556 | /* we sent our probe so now we just wait for receiving data only */ 557 | ev_uinet_stop(loop, &conn->watcher); 558 | ev_uinet_set(&conn->watcher, conn->soctx, EV_READ); 559 | ev_uinet_start(loop, &conn->watcher); 560 | } 561 | 562 | static void 563 | sniffer_cb(char * reject, const struct pcap_pkthdr * h, 564 | const unsigned char * bytes) 565 | { 566 | char buf[32]; 567 | struct uinet_in_addr in; 568 | struct uinet_sockaddr_in sin; 569 | struct uinet_socket * so; 570 | struct ev_uinet_ctx * soctx; 571 | struct connection * conn; 572 | struct ip * iph; 573 | struct tcphdr * tcph; 574 | struct ether_header * eth; 575 | uint32_t cookie, ack; 576 | uint16_t iplen, iphlen; 577 | size_t len; 578 | int ret; 579 | 580 | /* only support EtherNET frames */ 581 | len = h->caplen; 582 | if (len < sizeof(struct ether_header)) return; 583 | eth = (struct ether_header *)bytes; 584 | 585 | /* check if it's an IP frame */ 586 | if (ntohs(eth->ether_type) != 0x800) return; 587 | 588 | len -= sizeof(struct ether_header); 589 | bytes += sizeof(struct ether_header); 590 | if (len < sizeof(struct ip)) return; 591 | iph = (struct ip *)bytes; 592 | 593 | /* check if it's a TCP packet */ 594 | if (iph->ip_p != IPPROTO_TCP) return; 595 | 596 | /* check IP length fields */ 597 | iplen = ntohs(iph->ip_len); 598 | iphlen = iph->ip_hl << 2; 599 | if (iplen > len || iphlen > len) return; 600 | 601 | len -= iphlen; 602 | bytes += iphlen; 603 | if (len < sizeof(struct tcphdr)) return; 604 | tcph = (struct tcphdr *)(bytes); 605 | 606 | /* only care about SYN|ACK packets */ 607 | if ((tcph->th_flags & (TH_SYN|TH_ACK)) != (TH_SYN|TH_ACK)) { 608 | return; 609 | } 610 | 611 | /* 4-tuple arguments are switched as it should be a reply */ 612 | cookie = calc_cookie(iph->ip_dst.s_addr, iph->ip_src.s_addr, 613 | tcph->th_dport, tcph->th_sport); 614 | 615 | /* compare ACKs if it matches it's a reply to one of our probes */ 616 | ack = ntohl(tcph->th_ack) - 1; 617 | if (ack != cookie) { 618 | /* invalid SYN|ACK received so reject it */ 619 | *reject = 1; 620 | return; 621 | } 622 | 623 | in.s_addr = iph->ip_src.s_addr; 624 | memset(buf, 0, sizeof(buf)); 625 | uinet_inet_ntoa(in, buf, sizeof(buf)); 626 | VERBOSE("open port found at: %s:%u (cookie: 0x%x, ttl: %u)\n", buf, 627 | ntohs(tcph->th_sport), cookie, iph->ip_ttl); 628 | 629 | total_ack_received++; 630 | 631 | /* create a non-blocking uinet socket */ 632 | memset(&sin, 0, sizeof(struct uinet_sockaddr_in)); 633 | sin.sin_len = sizeof(struct uinet_sockaddr_in); 634 | sin.sin_family = UINET_AF_INET; 635 | sin.sin_addr.s_addr = iph->ip_src.s_addr; 636 | sin.sin_port = tcph->th_sport; 637 | ret = uinet_socreate(uinet_instance_default(), UINET_PF_INET, &so, 638 | UINET_SOCK_STREAM, UINET_IPPROTO_TCP); 639 | if (ret) { 640 | WARN("uinet_socreate failed"); 641 | return; 642 | } 643 | uinet_sosetnonblocking(so, 1); 644 | 645 | ret = uinet_fake_soconnect(so, (struct uinet_sockaddr *)&sin, 646 | tcph->th_dport, htonl(ack)); 647 | if (ret && ret != UINET_EADDRINUSE) { 648 | WARN("fake uinet connect failed: %i", ret); 649 | return; 650 | } 651 | 652 | soctx = ev_uinet_attach(so); 653 | if (NULL == soctx) { 654 | WARN("ev_uinet_attach failed\n"); 655 | return; 656 | } 657 | 658 | /* create new connection and attach it to the event loop */ 659 | conn = malloc(sizeof(*conn)); 660 | if (!conn) pfatal("malloc"); 661 | conn->soctx = soctx; 662 | conn->so = so; 663 | conn->counted = 0; 664 | tai_now(&conn->ts); 665 | ev_init(&conn->watcher, connection_cb); 666 | ev_uinet_set(&conn->watcher, conn->soctx, 667 | scan_mode == 'B' ? EV_READ : EV_WRITE); 668 | conn->watcher.data = conn; 669 | ev_uinet_start(loop, &conn->watcher); 670 | 671 | /* add connection to head of linked list */ 672 | conn->next = first_connection; 673 | conn->prev = NULL; 674 | if (first_connection) conn->next->prev = conn; 675 | first_connection = conn; 676 | 677 | total_active_connections++; 678 | } 679 | 680 | static void 681 | scanner_break_cb(EV_P_ ev_timer * w, int events) 682 | { 683 | char addrbuf[32]; 684 | struct connection * conn, * next; 685 | struct tai now; 686 | struct uinet_in_conninfo inc; 687 | 688 | VERBOSE("playing Queen; I want to break freeeheee!!!...\n"); 689 | 690 | /* clean up active connections but print out status line for them */ 691 | conn = first_connection; 692 | tai_now(&now); 693 | while (conn) { 694 | uinet_sogetconninfo(conn->so, &inc); 695 | OUT("%s:%u (killed: %zus)\n", 696 | uinet_inet_ntoa(inc.inc_ie.ie_faddr, addrbuf, 697 | sizeof(addrbuf)), ntohs(inc.inc_ie.ie_fport), 698 | ((size_t)(now.x - conn->ts.x)) 699 | ); 700 | ev_uinet_stop(loop, &conn->watcher); 701 | uinet_soclose(conn->so); 702 | ev_uinet_detach(conn->soctx); 703 | total_active_connections--; 704 | next = conn->next; 705 | free(conn); 706 | conn = next; 707 | } 708 | 709 | ev_break(EV_A_ EVBREAK_ONE); 710 | } 711 | 712 | static void 713 | scanner_done_cb(EV_P_ ev_timer * w, int events) 714 | { 715 | struct tai now; 716 | 717 | if (scanner_done) { 718 | 719 | tai_now(&now); 720 | 721 | /* give the grabber thread 1 second to catch up on incoming 722 | ACKs and if no ACKs have come in and there are no active 723 | connections left bail out immediately */ 724 | if (now.x - scanner_done_time.x >= 1 && 725 | !total_active_connections) { 726 | VERBOSE("scanner is done and no active sockets left\n"); 727 | ev_break(EV_A_ EVBREAK_ONE); 728 | } 729 | 730 | /* if it's not set yet set the timeout for the final break out 731 | of the event loop regardless of how many active connections 732 | are still open */ 733 | if (!ev_is_active(&scanner_break)) { 734 | VERBOSE("scanner is done... cleaning up remaining sockets\n"); 735 | ev_timer_init(&scanner_break, scanner_break_cb, 736 | timeout, 0); 737 | ev_timer_start(loop, &scanner_break); 738 | } 739 | } 740 | } 741 | 742 | static void 743 | scanner_stdin(EV_P_ ev_io * w, int events) 744 | { 745 | char buf[4096]; 746 | 747 | read(STDIN_FILENO, &buf, sizeof(buf)); 748 | 749 | OUT("sent: %2.2f%% (of %zu), open: %zu, active: %zu, acks: %zu\n", 750 | total_syn_todo?( 751 | (double)total_syn_sent/ 752 | (double)total_syn_todo * 100.0):0.0, 753 | total_syn_todo, 754 | total_open_ports_found, 755 | total_active_connections, 756 | total_ack_received 757 | ); 758 | } 759 | 760 | static void 761 | scanner_start_cb(EV_P_ ev_timer * w, int events) 762 | { 763 | if (pthread_create(&threads[0], NULL, scanner, NULL)) 764 | pfatal("pthread_create"); 765 | } 766 | 767 | static void * 768 | grabber(void * arg) 769 | { 770 | ev_timer scanner_done_watcher, scanner_start_watcher; 771 | ev_io stdin_watcher; 772 | const char * iface = (char *)arg; 773 | char * ip, * bcast, * mask; 774 | int ret; 775 | 776 | /* get interface information */ 777 | ret = get_iface_addrs(iface, &ip, &bcast, &mask); 778 | if (ret < 0) { 779 | fprintf(err, "error while getting interface addresses!\n"); 780 | return NULL; 781 | } 782 | src_ip = inet_addr(ip); 783 | bcast_ip = inet_addr(bcast); 784 | mask_ip = inet_addr(mask); 785 | 786 | /* setup uinet */ 787 | ret = uinet_init(32, 128*1024, NULL); 788 | if (ret) { 789 | fprintf(err, "error while initting libuinet\n"); 790 | return NULL; 791 | } 792 | uinet_install_sighandlers(); 793 | 794 | /* construct PCAP interface on the right interface with the right 795 | settings such that uinet can start capturing packets for us */ 796 | ret = uinet_ifcreate(uinet_instance_default(), UINET_IFTYPE_PCAP, iface, 797 | "iface", 1, 1, NULL); /* first 1 is cdom */ 798 | if (ret) { 799 | fprintf(err, "error while creating iface\n"); 800 | return NULL; 801 | } 802 | ret = uinet_interface_add_alias(uinet_instance_default(), "iface", 803 | ip, bcast, mask); 804 | free(ip); 805 | free(bcast); 806 | free(mask); 807 | if (ret) { 808 | fprintf(err, "error while adding iface alias\n"); 809 | return NULL; 810 | } 811 | ret = uinet_interface_up(uinet_instance_default(), "iface", 0, 0); 812 | if (ret) { 813 | fprintf(err, "cannot put up interface\n"); 814 | return NULL; 815 | } 816 | ret = uinet_if_set_pcap_handler(uinet_instance_default(), "iface", sniffer_cb); 817 | if (ret) { 818 | fprintf(err, "error while setting pcap handler\n"); 819 | return NULL; 820 | } 821 | 822 | /* set route information in uinet */ 823 | route(gateway); 824 | 825 | VERBOSE("done setting up uinet... starting event loop\n"); 826 | 827 | loop = ev_default_loop(0); 828 | 829 | VERBOSE("created default loop!!\n"); 830 | 831 | /* check every 1/2 second whether scanner thread is done */ 832 | ev_timer_init(&scanner_done_watcher, scanner_done_cb, 0.5, 1); 833 | ev_timer_start(loop, &scanner_done_watcher); 834 | 835 | /* ugly but needed to kick off scanner after event loop is set up */ 836 | ev_timer_init(&scanner_start_watcher, scanner_start_cb, 0.01, 0); 837 | ev_timer_start(loop, &scanner_start_watcher); 838 | 839 | /* read from stdin for printing of stats */ 840 | ev_io_init(&stdin_watcher, scanner_stdin, 0, EV_READ); 841 | ev_io_start(loop, &stdin_watcher); 842 | 843 | VERBOSE("started running main event loop\n"); 844 | ev_run(loop, 0); 845 | 846 | VERBOSE("done with main event loop\n"); 847 | 848 | /* clean up */ 849 | ev_default_destroy(); 850 | uinet_shutdown(0); 851 | 852 | return NULL; 853 | } 854 | 855 | static void 856 | exec_iptables(char ** argvp) 857 | { 858 | int ret, status; 859 | pid_t pid; 860 | 861 | pid = fork(); 862 | if (pid == -1) pfatal("fork"); 863 | if (!pid) { 864 | ret = execve(IPTABLES, argvp, NULL); 865 | if (ret < 0) pfatal("execve"); 866 | exit(EXIT_FAILURE); 867 | } 868 | 869 | ret = waitpid(pid, &status, 0); 870 | if (ret == -1) pfatal("waitpid"); 871 | 872 | if (!WIFEXITED(status)) { 873 | fatal("iptables execution failed"); 874 | } 875 | ret = WEXITSTATUS(status); 876 | if (ret) { 877 | fatal("iptables execution returned error code"); 878 | } 879 | } 880 | 881 | inline static void 882 | set_iptables_rule() 883 | { 884 | char * argvp[] = IPTABLES_ARG; 885 | argvp[1] = "-A"; 886 | exec_iptables(argvp); 887 | } 888 | 889 | inline static void 890 | unset_iptables_rule() 891 | { 892 | char * argvp[] = IPTABLES_ARG; 893 | argvp[1] = "-D"; 894 | exec_iptables(argvp); 895 | } 896 | 897 | static void 898 | sig_handler(int sig) 899 | { 900 | quit = 1; 901 | } 902 | 903 | static void 904 | usage(const char * arg0) 905 | { 906 | fprintf(stderr, "%s [options] \n\n", arg0); 907 | fprintf(stderr, " target can be specified as:\n"); 908 | fprintf(stderr, " 10.1.2.3; 10.0.0.2-10.0.255.255; 10.0.0.1/24\n\n"); 909 | fprintf(stderr, "Main options:\n"); 910 | fprintf(stderr, "-sB/sH/sT/sC - scan mode (default: -sB)\n"); 911 | fprintf(stderr, " Modes: B=Banner, H=HTTP, T=TLS, C=Custom\n"); 912 | fprintf(stderr, "-p - list of ports to scan\n"); 913 | fprintf(stderr, " Ex: -p22; -p21-80,443,1024-2048,8080\n"); 914 | fprintf(stderr, "-b - outgoing bandwidth limit\n"); 915 | fprintf(stderr, " Ex: -b300k; -b67m; -b500b (300kbps, 67mbps, "); 916 | fprintf(stderr, "500bps)\n"); 917 | fprintf(stderr, "-d - file containing data to send "); 918 | fprintf(stderr, "(-sC only)\n"); 919 | fprintf(stderr, "-t - timeout in seconds (default: 30)\n"); 920 | fprintf(stderr, "-v - verbose output\n"); 921 | fprintf(stderr, "-x - always output banners in hex mode"); 922 | fprintf(stderr, "\n\nAuxiliary options:\n"); 923 | fprintf(stderr, "-i - capture interface to use\n"); 924 | fprintf(stderr, "-r - random seed to use (can be in decimal or hex)\n"); 925 | fprintf(stderr, "-T - IP TTL (default: 64)\n"); 926 | fprintf(stderr, "-W - TCP Window size (default: 65535)\n"); 927 | fprintf(stderr, "-I - IP ID (default: 12345)\n"); 928 | fprintf(stderr, "-n - neglect setting RST drop rule\n"); 929 | fprintf(stderr, "-o - show internal uinet output\n"); 930 | fprintf(stderr, "-h - this screen\n"); 931 | fprintf(stderr, "\n"); 932 | fflush(stderr); 933 | exit(EXIT_FAILURE); 934 | } 935 | 936 | int 937 | main(int argc, char ** argv) 938 | { 939 | char * portrange_str = DEFAULT_PORTRANGE; 940 | char * iface = NULL, * gw = NULL, * ip = NULL; 941 | char * bw_end = NULL, * bw_arg = NULL; 942 | char * custom_data_fn = NULL; 943 | long int j, mult = 0; 944 | int c, i, ret, seed_set, status, outfd, errfd; 945 | int redirout, setiptables; 946 | struct sigaction sa; 947 | pid_t pid; 948 | 949 | /* set the iptables rule and redirect stdout by default */ 950 | setiptables = 1; 951 | redirout = 1; 952 | 953 | /* no seed set by default */ 954 | seed_set = 0; 955 | 956 | out = stdout; 957 | err = stderr; 958 | 959 | /* set default probe values */ 960 | ip_id_value = htons(54321); 961 | ip_ttl_value = 64; 962 | tcp_win_value = htons(65535); 963 | 964 | /* default scan mode is the banner scan */ 965 | scan_mode = 'B'; 966 | 967 | /* default timeout in seconds */ 968 | timeout = 30.0; 969 | 970 | fprintf(out, "polarbearscan %s -- gvb@santarago.org\n\n", 971 | polarbearscan_version); 972 | 973 | while ((c = getopt(argc, argv, "vnohxi:r:p:s:b:t:d:I:T:W:")) != -1) { 974 | switch (c) { 975 | case 'I': 976 | errno = 0; 977 | j = strtol(optarg, NULL, 10); 978 | if (errno || j < 0 || j > 65535) { 979 | fprintf(stderr, "invalid IP ID value\n"); 980 | usage(argc > 0 ? argv[0] : "(unknown)"); 981 | } 982 | ip_id_value = htons(j); 983 | break; 984 | case 'T': 985 | errno = 0; 986 | j = strtol(optarg, NULL, 10); 987 | if (errno || j < 0 || j > 255) { 988 | fprintf(stderr, "invalid IP TTL value\n"); 989 | usage(argc > 0 ? argv[0] : "(unknown)"); 990 | } 991 | ip_ttl_value = j; 992 | break; 993 | case 'W': 994 | errno = 0; 995 | j = strtol(optarg, NULL, 10); 996 | if (errno || j < 0 || j > 65535) { 997 | fprintf(stderr, "invalid TCP Window value\n"); 998 | usage(argc > 0 ? argv[0] : "(unknown)"); 999 | } 1000 | tcp_win_value = htons(j); 1001 | break; 1002 | case 'd': 1003 | custom_data_fn = optarg; 1004 | break; 1005 | case 'b': 1006 | bw_arg = optarg; 1007 | break; 1008 | case 's': 1009 | scan_mode = *optarg; 1010 | if (scan_mode != 'B' && scan_mode != 'H' 1011 | && scan_mode != 'T' 1012 | && scan_mode != 'C') { 1013 | fprintf(stderr, "invalid scan mode\n"); 1014 | usage(argc > 0 ? argv[0] : "(unknown)"); 1015 | } 1016 | break; 1017 | case 'p': 1018 | portrange_str = optarg; 1019 | break; 1020 | case 'i': 1021 | iface = optarg; 1022 | break; 1023 | case 'r': 1024 | errno = 0; 1025 | /* support hex (prefixed with 0x) and decimal */ 1026 | j = strtol(optarg, NULL, 1027 | (strlen(optarg) > 2 && 1028 | *optarg=='0' && *optarg+1=='x') ? 16 : 0); 1029 | if (errno) { 1030 | fprintf(stderr, "invalid seed\n"); 1031 | usage(argc > 0 ? argv[0] : "(unknown)"); 1032 | } 1033 | rand_seed = (uint32_t)j; 1034 | seed_set = 1; 1035 | break; 1036 | case 'n': 1037 | setiptables = 0; 1038 | break; 1039 | case 'o': 1040 | redirout = 0; 1041 | break; 1042 | case 'x': 1043 | force_hex_output = 1; 1044 | break; 1045 | case 't': 1046 | errno = 0; 1047 | j = strtol(optarg, NULL, 0); 1048 | if (errno) { 1049 | fprintf(stderr, "invalid timeout\n"); 1050 | usage(argc > 0 ? argv[0] : "(unknown)"); 1051 | } 1052 | if (j < 0 || j > (5*60)) 1053 | fatal("maximum timeout is 5 minutes"); 1054 | timeout = (double)j; 1055 | break; 1056 | case 'v': 1057 | verbose = 1; 1058 | break; 1059 | case 'h': 1060 | default: 1061 | usage(argc > 0 ? argv[0] : "(unknown)"); 1062 | break; 1063 | } 1064 | } 1065 | 1066 | /* parse target IP range */ 1067 | if (optind == argc) fatal("no target IP-range specified"); 1068 | ret = iprange_parse(argv[optind], &ip_range); 1069 | if (ret < 0) fatal("error while parsing IP-range"); 1070 | 1071 | /* parse target port range */ 1072 | ret = portrange_parse(portrange_str, &port_range); 1073 | if (ret < 0) fatal("error while parsing port range"); 1074 | 1075 | /* load custom data from file if needed */ 1076 | if (scan_mode == 'C') { 1077 | if (!custom_data_fn) 1078 | fatal("-sC cannot be used without -d"); 1079 | 1080 | /* 128kB should be more than enough */ 1081 | custom_data_len = 128*1024; 1082 | ret = read_full_file(custom_data_fn, &custom_data, 1083 | &custom_data_len, 1); 1084 | if (ret < 0) fatal("cannot read data file"); 1085 | } 1086 | else if (custom_data_fn) { 1087 | fatal("-d can only be used in conjuction with -sC"); 1088 | } 1089 | 1090 | /* parse bandwith limitation option if set */ 1091 | if (bw_arg) { 1092 | if (!strlen(bw_arg)) fatal("invalid bandwidth option"); 1093 | c = tolower(bw_arg[strlen(bw_arg)-1]); 1094 | switch (c) { 1095 | case 'b': 1096 | mult = 1; 1097 | break; 1098 | case 'k': 1099 | mult = 1024; 1100 | break; 1101 | case 'm': 1102 | mult = (1024*1024); 1103 | break; 1104 | case 'g': 1105 | mult = (1024*1024*1024); 1106 | break; 1107 | default: 1108 | fatal("invalid bandwidth option"); 1109 | } 1110 | bw_arg[strlen(bw_arg)-1]=0; 1111 | errno = 0; 1112 | j = strtol(bw_arg, &bw_end, 0); 1113 | if (errno != 0 || bw_end != bw_arg+strlen(bw_arg)) 1114 | fatal("error while parsing bandwidth option"); 1115 | if (!j) fatal("cannot set bandwidth to 0 bytes per second"); 1116 | 1117 | /* frame size for each SYN probe is 64 bytes (minimum 1118 | size of Ethernet frame) so we calculate the amount of 1119 | time we need to sleep in between probes such that we 1120 | end up at the required bandwidth usage. 1121 | */ 1122 | sleep_between_pkts = ((1000000 / (j * mult))*64); 1123 | 1124 | if (sleep_between_pkts > 5000000) { 1125 | fatal("bandwidth limit set too low"); 1126 | } 1127 | } 1128 | 1129 | /* detect interface and/or gateway if necessary */ 1130 | ret = get_default_gw(&iface, &gw); 1131 | if (ret < 0) fatal("cannot detect interface and gateway"); 1132 | gateway = gw; 1133 | gw_ip = inet_addr(gateway); 1134 | 1135 | /* I don't really care about proper randomness; I'd rather 1136 | be able to reproduce exact packet output by being able to 1137 | to reuse the same seed so everywhere just use rand_r() 1138 | for generation PRNG values. 1139 | */ 1140 | if (!seed_set) { 1141 | rand_seed = get_rand_uint32(); 1142 | } 1143 | 1144 | /* output settings used for this scan */ 1145 | fprintf(out, "seed: 0x%x, iface: %s, src: ", rand_seed, iface); 1146 | ret = get_iface_addrs(iface, &ip, NULL, NULL); 1147 | if (ret < 0) fatal("error while getting interface addresses!\n"); 1148 | fprintf(out, "%s (id: %u, ttl: %u, win: %u)\n", ip, 1149 | ntohs(ip_id_value), ip_ttl_value, ntohs(tcp_win_value)); 1150 | free(ip); 1151 | 1152 | if (scan_mode == 'C') { 1153 | VERBOSE("using %zu bytes of data for custom scan\n", 1154 | custom_data_len); 1155 | } 1156 | 1157 | /* get a secret key */ 1158 | for (i=0;i> 8) & 0xff); 1162 | secret_key[i+2] = ((j >> 16) & 0xff); 1163 | secret_key[i+3] = ((j >> 24) & 0xff); 1164 | } 1165 | 1166 | /* If we need to set the IP tables firewall entry to drop RST packets 1167 | we need to setup a parent process such that we can monitor the child 1168 | and remove the IP table entry when the child is done. This is pretty 1169 | dirty but barring any abnormal termination of the parent (SIGSEGV 1170 | f.e.) it will properly remove the firewall entry. */ 1171 | if (setiptables) { 1172 | pid = fork(); 1173 | if (pid == -1) pfatal("fork"); 1174 | if (pid) { 1175 | 1176 | /* set the IP tables entry */ 1177 | set_iptables_rule(); 1178 | 1179 | /* install signal handler */ 1180 | sa.sa_handler = sig_handler; 1181 | sigemptyset(&sa.sa_mask); 1182 | sa.sa_flags = 0; 1183 | if (sigaction(SIGINT, &sa, NULL) == -1) 1184 | pfatal("sigaction"); 1185 | if (sigaction(SIGTERM, &sa, NULL) == -1) 1186 | pfatal("sigaction"); 1187 | 1188 | /* wait until child is done or we're killed */ 1189 | do { 1190 | ret = waitpid(pid, &status, 0); 1191 | if (quit) break; 1192 | } while (ret == EINTR || (!WIFEXITED(status) && 1193 | !WIFSIGNALED(status))); 1194 | 1195 | /* if we're killed terminate the child too */ 1196 | if (quit) { 1197 | ret = kill(pid, SIGTERM); 1198 | if (ret < 0) pfatal("kill"); 1199 | do { 1200 | ret = waitpid(pid, &status, 0); 1201 | } while (!WIFEXITED(status) && 1202 | !WIFSIGNALED(status)); 1203 | } 1204 | 1205 | /* reset the IP tables */ 1206 | unset_iptables_rule(); 1207 | exit(EXIT_SUCCESS); 1208 | } 1209 | } 1210 | 1211 | /* hide libuinet stdout/stderr if necessary */ 1212 | if (redirout) { 1213 | ret = close(0); 1214 | if (ret < 0) pfatal("close"); 1215 | outfd = dup(1); 1216 | if (outfd < 0) pfatal("dup"); 1217 | errfd = dup(2); 1218 | if (errfd < 0) pfatal("dup"); 1219 | ret = close(1); 1220 | if (ret < 0) pfatal("close"); 1221 | ret = close(2); 1222 | if (ret < 0) pfatal("close"); 1223 | out = fdopen(outfd, "w"); 1224 | if (!out) fatal("fdopen"); 1225 | err = fdopen(errfd, "w"); 1226 | if (!err) fatal("fdopen"); 1227 | } 1228 | 1229 | /* get raw socket for pumping out SYN packets */ 1230 | raw_fd = get_raw_fd(); 1231 | 1232 | /* run grabber thread which captures the packets */ 1233 | grabber((void *)iface); 1234 | 1235 | /* clean up after ourselves */ 1236 | for (i=0;i 24 | 100% Public Domain 25 | 26 | Test Vectors (from FIPS PUB 180-1) 27 | "abc" 28 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 29 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 30 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 31 | A million repetitions of "a" 32 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 33 | */ 34 | 35 | /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ 36 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 37 | 38 | #define SHA1HANDSOFF 39 | 40 | #include 41 | #include 42 | #include 43 | #include "sha1.h" 44 | 45 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 46 | 47 | /* blk0() and blk() perform the initial expand. */ 48 | /* I got the idea of expanding during the round function from SSLeay */ 49 | #if BYTE_ORDER == LITTLE_ENDIAN 50 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ 51 | |(rol(block->l[i],8)&0x00FF00FF)) 52 | #elif BYTE_ORDER == BIG_ENDIAN 53 | #define blk0(i) block->l[i] 54 | #else 55 | #error "Endianness not defined!" 56 | #endif 57 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 58 | ^block->l[(i+2)&15]^block->l[i&15],1)) 59 | 60 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 61 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 62 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 63 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 64 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 65 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 66 | 67 | 68 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 69 | 70 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) 71 | { 72 | uint32_t a, b, c, d, e; 73 | typedef union { 74 | unsigned char c[64]; 75 | uint32_t l[16]; 76 | } CHAR64LONG16; 77 | #ifdef SHA1HANDSOFF 78 | CHAR64LONG16 block[1]; /* use array to appear as a pointer */ 79 | memcpy(block, buffer, 64); 80 | #else 81 | /* The following had better never be used because it causes the 82 | * pointer-to-const buffer to be cast into a pointer to non-const. 83 | * And the result is written through. I threw a "const" in, hoping 84 | * this will cause a diagnostic. 85 | */ 86 | CHAR64LONG16* block = (const CHAR64LONG16*)buffer; 87 | #endif 88 | /* Copy context->state[] to working vars */ 89 | a = state[0]; 90 | b = state[1]; 91 | c = state[2]; 92 | d = state[3]; 93 | e = state[4]; 94 | /* 4 rounds of 20 operations each. Loop unrolled. */ 95 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); 96 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); 97 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); 98 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); 99 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); 100 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); 101 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); 102 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); 103 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); 104 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); 105 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); 106 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); 107 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); 108 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); 109 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); 110 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); 111 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); 112 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); 113 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); 114 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); 115 | /* Add the working vars back into context.state[] */ 116 | state[0] += a; 117 | state[1] += b; 118 | state[2] += c; 119 | state[3] += d; 120 | state[4] += e; 121 | /* Wipe variables */ 122 | a = b = c = d = e = 0; 123 | #ifdef SHA1HANDSOFF 124 | memset(block, '\0', sizeof(block)); 125 | #endif 126 | } 127 | 128 | 129 | /* SHA1Init - Initialize new context */ 130 | 131 | void SHA1Init(SHA1_CTX* context) 132 | { 133 | /* SHA1 initialization constants */ 134 | context->state[0] = 0x67452301; 135 | context->state[1] = 0xEFCDAB89; 136 | context->state[2] = 0x98BADCFE; 137 | context->state[3] = 0x10325476; 138 | context->state[4] = 0xC3D2E1F0; 139 | context->count[0] = context->count[1] = 0; 140 | } 141 | 142 | 143 | /* Run your data through this. */ 144 | 145 | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len) 146 | { 147 | uint32_t i, j; 148 | 149 | j = context->count[0]; 150 | if ((context->count[0] += len << 3) < j) 151 | context->count[1]++; 152 | context->count[1] += (len>>29); 153 | j = (j >> 3) & 63; 154 | if ((j + len) > 63) { 155 | memcpy(&context->buffer[j], data, (i = 64-j)); 156 | SHA1Transform(context->state, context->buffer); 157 | for ( ; i + 63 < len; i += 64) { 158 | SHA1Transform(context->state, &data[i]); 159 | } 160 | j = 0; 161 | } 162 | else i = 0; 163 | memcpy(&context->buffer[j], &data[i], len - i); 164 | } 165 | 166 | 167 | /* Add padding and return the message digest. */ 168 | 169 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context) 170 | { 171 | unsigned i; 172 | unsigned char finalcount[8]; 173 | unsigned char c; 174 | 175 | #if 0 /* untested "improvement" by DHR */ 176 | /* Convert context->count to a sequence of bytes 177 | * in finalcount. Second element first, but 178 | * big-endian order within element. 179 | * But we do it all backwards. 180 | */ 181 | unsigned char *fcp = &finalcount[8]; 182 | 183 | for (i = 0; i < 2; i++) 184 | { 185 | uint32_t t = context->count[i]; 186 | int j; 187 | 188 | for (j = 0; j < 4; t >>= 8, j++) 189 | *--fcp = (unsigned char) t; 190 | } 191 | #else 192 | for (i = 0; i < 8; i++) { 193 | finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] 194 | >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ 195 | } 196 | #endif 197 | c = 0200; 198 | SHA1Update(context, &c, 1); 199 | while ((context->count[0] & 504) != 448) { 200 | c = 0000; 201 | SHA1Update(context, &c, 1); 202 | } 203 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 204 | for (i = 0; i < 20; i++) { 205 | digest[i] = (unsigned char) 206 | ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); 207 | } 208 | /* Wipe variables */ 209 | memset(context, '\0', sizeof(*context)); 210 | memset(&finalcount, '\0', sizeof(finalcount)); 211 | } 212 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | /* ================ sha1.h ================ */ 21 | /* 22 | SHA-1 in C 23 | By Steve Reid 24 | 100% Public Domain 25 | */ 26 | 27 | typedef struct { 28 | uint32_t state[5]; 29 | uint32_t count[2]; 30 | unsigned char buffer[64]; 31 | } SHA1_CTX; 32 | 33 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); 34 | void SHA1Init(SHA1_CTX* context); 35 | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); 36 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context); 37 | -------------------------------------------------------------------------------- /time.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | /* The tai and taia routines are based on djb's libtai which is placed in the 21 | * public domain. See http://cr.yp.to/libtai.html for details. The taia code 22 | * was slightly modified to only take into account nano-second based timing. 23 | * All the atto-second related code was removed to save some space when packing 24 | * taia structures on disk. */ 25 | 26 | #define _XOPEN_SOURCE /* needed for strptime */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "time.h" 36 | 37 | void 38 | tai_now(struct tai * t) 39 | { 40 | tai_unix(t, time((time_t *)0)); 41 | } 42 | 43 | void 44 | tai_pack(char * s, const struct tai * t) 45 | { 46 | uint64_t x; 47 | 48 | x = t->x; 49 | s[7] = x & 255; x >>= 8; 50 | s[6] = x & 255; x >>= 8; 51 | s[5] = x & 255; x >>= 8; 52 | s[4] = x & 255; x >>= 8; 53 | s[3] = x & 255; x >>= 8; 54 | s[2] = x & 255; x >>= 8; 55 | s[1] = x & 255; x >>= 8; 56 | s[0] = x; 57 | } 58 | 59 | void 60 | tai_unpack(const char * s, struct tai * t) 61 | { 62 | uint64_t x; 63 | 64 | x = (unsigned char)s[0]; 65 | x <<= 8; x += (unsigned char) s[1]; 66 | x <<= 8; x += (unsigned char) s[2]; 67 | x <<= 8; x += (unsigned char) s[3]; 68 | x <<= 8; x += (unsigned char) s[4]; 69 | x <<= 8; x += (unsigned char) s[5]; 70 | x <<= 8; x += (unsigned char) s[6]; 71 | x <<= 8; x += (unsigned char) s[7]; 72 | t->x = x; 73 | } 74 | 75 | void 76 | taia_now(struct taia * t) 77 | { 78 | struct timeval now; 79 | gettimeofday(&now, (struct timezone *) 0); 80 | tai_unix(&t->sec, now.tv_sec); 81 | t->nano = 1000 * now.tv_usec + 500; 82 | } 83 | 84 | void 85 | taia_pack(char * s, const struct taia * t) 86 | { 87 | unsigned long x; 88 | 89 | tai_pack(s, &t->sec); 90 | s += 8; 91 | 92 | x = t->nano; 93 | s[3] = x & 255; x >>= 8; 94 | s[2] = x & 255; x >>= 8; 95 | s[1] = x & 255; x >>= 8; 96 | s[0] = x; 97 | } 98 | 99 | void 100 | taia_unpack(const char * s, struct taia * t) 101 | { 102 | unsigned long x; 103 | 104 | tai_unpack(s, &t->sec); 105 | s += 8; 106 | 107 | x = (unsigned char)s[0]; 108 | x <<= 8; x += (unsigned char)s[1]; 109 | x <<= 8; x += (unsigned char)s[2]; 110 | x <<= 8; x += (unsigned char)s[3]; 111 | t->nano = x; 112 | } 113 | 114 | int 115 | taia_less(struct taia * t, struct taia * u) 116 | { 117 | if (t->sec.x < u->sec.x) return 1; 118 | if (t->sec.x > u->sec.x) return 0; 119 | return t->nano < u->nano; 120 | } 121 | 122 | int 123 | taia_leq(struct taia * t, struct taia * u) 124 | { 125 | if (t->sec.x <= u->sec.x) return 1; 126 | if (t->sec.x > u->sec.x) return 0; 127 | return t->nano <= u->nano; 128 | } 129 | 130 | void 131 | taia_diff(struct taia * t, struct taia * u, struct taia * res) 132 | { 133 | res->sec.x = u->sec.x - t->sec.x; 134 | res->nano = u->nano - t->nano; 135 | } 136 | 137 | int 138 | timestr_parse(const char * input, struct taia * res, struct taia * b) 139 | { 140 | struct taia base, * pbase; 141 | const char * p; 142 | uint32_t w, d, h, m, s; 143 | unsigned int n; 144 | 145 | if (!input || !res) return -1; 146 | if (b) pbase = b; 147 | else { 148 | taia_now(&base); 149 | pbase = &base; 150 | } 151 | p = input; 152 | w = d = h = m = s = 0; 153 | 154 | next: 155 | n = 0; 156 | while (*p && (*p >= '0' && *p <= '9')) { 157 | n *= 10; 158 | n += (*p-'0'); 159 | p++; 160 | } 161 | if (!*p) return -1; 162 | 163 | switch (*p) { 164 | case 'w': 165 | if ((d*h*m*s)!=0) return -1; 166 | w = n*604800; 167 | break; 168 | case 'd': 169 | if ((h*m*s)!=0) return -1; 170 | d = n*86400; 171 | break; 172 | case 'h': 173 | if ((m*s)!=0) return -1; 174 | h = n*3600; 175 | break; 176 | case 'm': 177 | if (s) return -1; 178 | m = n*60; 179 | break; 180 | case 's': 181 | s = n; 182 | break; 183 | default: 184 | return -1; 185 | } 186 | if (*++p) goto next; 187 | 188 | res->sec.x = pbase->sec.x - (w+d+h+m+s); 189 | res->nano = pbase->nano; 190 | 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #ifndef TIME_H 21 | #define TIME_H 22 | 23 | #include 24 | 25 | /* The tai and taia routines are based on djb's libtai which is placed in the 26 | * public domain. See http://cr.yp.to/libtai.html for details. The taia code 27 | * was slightly modified to only take into account nano-second based timing. 28 | * All the atto-second related code was removed to save some space when packing 29 | * taia structures on disk. */ 30 | 31 | struct tai { 32 | uint64_t x; 33 | }; 34 | 35 | void tai_now(struct tai *); 36 | #define TAI_PACK 8 37 | void tai_pack(char *, const struct tai *); 38 | void tai_unpack(const char *, struct tai *); 39 | 40 | #define tai_unix(t,u) ((void)((t)->x = 4611686018427387914ULL + (uint64_t)(u))) 41 | 42 | struct taia { 43 | struct tai sec; 44 | unsigned long nano; /* 0...999999999 */ 45 | }; 46 | 47 | void taia_now(struct taia *); 48 | 49 | #define TAIA_PACK 12 50 | void taia_pack(char *, const struct taia *); 51 | void taia_unpack(const char *, struct taia *); 52 | 53 | int taia_less(struct taia *, struct taia *); 54 | int taia_leq(struct taia *, struct taia *); 55 | 56 | void taia_diff(struct taia *, struct taia *, struct taia *); 57 | 58 | int timestr_parse(const char *, struct taia *, struct taia *); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /tls.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #ifndef TLS_H 21 | #define TLS_H 22 | 23 | /* list of TLS alert/error codes so some more user-friendly decoding 24 | is possible when doing a TLS scan */ 25 | 26 | struct { 27 | int code; 28 | const char * desc; 29 | } tls_error_codes[] = { 30 | {10,"Unexpected message"}, 31 | {20,"Bad record MAC"}, 32 | {21,"Decryption failed"}, 33 | {22,"Record overflow"}, 34 | {30,"Decompression failure"}, 35 | {40,"Handshake failure"}, 36 | {41,"No certificate"}, 37 | {42,"Bad certificate"}, 38 | {43,"Unsupported certificate"}, 39 | {44,"Certificate revoked"}, 40 | {45,"Certificate expired"}, 41 | {46,"Certificate unknown"}, 42 | {47,"Illegal parameter"}, 43 | {48,"Unknown CA"}, 44 | {49,"Access denied"}, 45 | {50,"Decode error"}, 46 | {51,"Decrypt error"}, 47 | {60,"Export restriction"}, 48 | {70,"Protocol version"}, 49 | {71,"Insufficient security"}, 50 | {80,"Internal error"}, 51 | {90,"User canceled"}, 52 | {100,"No renegotiation"}, 53 | {110,"Unsupported extension"}, 54 | {111,"Certificate unobtainable"}, 55 | {112,"Unrecognized name"}, 56 | {113,"Bad certificate status response"}, 57 | {114,"Bad certificate hash value"}, 58 | {115,"Unknown PSK identity"}, 59 | {120,"No Application Protocol"}, 60 | {0, NULL} 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | extern FILE * err; 34 | 35 | void 36 | fatal(const char * line) 37 | { 38 | fprintf(err, "%s\n", line); 39 | fflush(err); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | void 44 | pfatal(const char * line) 45 | { 46 | perror(line); 47 | fflush(err); 48 | exit(EXIT_FAILURE); 49 | } 50 | 51 | int 52 | get_raw_fd() 53 | { 54 | int fd, ret, one; 55 | 56 | fd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); 57 | if (fd < 0) pfatal("socket"); 58 | 59 | one = 1; 60 | ret = setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); 61 | if (ret < 0) pfatal("setsockopt"); 62 | 63 | return fd; 64 | } 65 | 66 | int 67 | get_default_gw(char ** iface, char ** gw) 68 | { 69 | FILE * f; 70 | char line[100], * ret, * p, * striface = NULL, * strgw = NULL; 71 | struct in_addr in; 72 | int check_iface; 73 | 74 | check_iface = (iface && *iface && strlen(*iface) > 0); 75 | 76 | f = fopen("/proc/net/route", "r"); 77 | if (!f) return -1; 78 | 79 | while (!feof(f)) { 80 | ret = fgets(line, 100, f); 81 | if (!ret) return -1; 82 | 83 | p = line; 84 | while (*p && *p != ' ' && *p != '\t') p++; 85 | if (!*p) continue; 86 | *p++ = 0; 87 | 88 | if (check_iface && strcmp(*iface, line)) 89 | continue; 90 | 91 | while (*p && (*p == ' ' || *p == '\t')) p++; 92 | if (!*p) continue; 93 | ret = p; 94 | 95 | while (*p && *p != ' ' && *p != '\t') p++; 96 | if (!*p) continue; 97 | *p++ = 0; 98 | 99 | if (strcmp(ret, "00000000")) continue; 100 | 101 | ret = p; 102 | while (*p && *p != ' ' && *p != '\t') p++; 103 | if (!*p) continue; 104 | *p++ = 0; 105 | 106 | in.s_addr = strtol(ret, NULL, 16); 107 | 108 | if (iface) { 109 | striface = strdup(line); 110 | if (!striface) goto errout; 111 | } 112 | 113 | if (gw) { 114 | strgw = strdup(inet_ntoa(in)); 115 | if (!strgw) goto errout; 116 | } 117 | 118 | *iface = striface; 119 | *gw = strgw; 120 | 121 | return 0; 122 | } 123 | 124 | errout: 125 | if (striface) free(striface); 126 | if (strgw) free(strgw); 127 | 128 | return -1; 129 | } 130 | 131 | int 132 | get_iface_addrs(const char * iface, char ** ip, char ** bcast, char ** mask) 133 | { 134 | char * strip = NULL, * strbcast = NULL; 135 | struct sockaddr_in * sin; 136 | struct ifreq ifr; 137 | int fd, ret; 138 | 139 | fd = socket(AF_INET, SOCK_DGRAM, 0); 140 | if (fd < 0) return -1; 141 | 142 | memset(&ifr, 0, sizeof(struct ifreq)); 143 | ifr.ifr_addr.sa_family = AF_INET; 144 | strncpy(ifr.ifr_name, iface, IFNAMSIZ-1); 145 | 146 | sin = (struct sockaddr_in *)&ifr.ifr_addr; 147 | 148 | /* IP */ 149 | if (ip) { 150 | ret = ioctl(fd, SIOCGIFADDR, &ifr); 151 | if (ret < 0) goto errout; 152 | strip = strdup(inet_ntoa(sin->sin_addr)); 153 | if (!strip) goto errout; 154 | } 155 | 156 | /* broadcast */ 157 | if (bcast) { 158 | ret = ioctl(fd, SIOCGIFBRDADDR, &ifr); 159 | if (ret < 0) goto errout; 160 | strbcast = strdup(inet_ntoa(sin->sin_addr)); 161 | if (!strbcast) goto errout; 162 | } 163 | 164 | /* netmask */ 165 | if (mask) { 166 | ret = ioctl(fd, SIOCGIFNETMASK, &ifr); 167 | if (ret < 0) goto errout; 168 | *mask = strdup(inet_ntoa(sin->sin_addr)); 169 | if (!*mask) goto errout; 170 | } 171 | 172 | if (bcast) *bcast = strbcast; 173 | if (ip) *ip = strip; 174 | 175 | close(fd); 176 | return 0; 177 | errout: 178 | close(fd); 179 | if (strip) free(strip); 180 | if (strbcast) free(strbcast); 181 | return -1; 182 | } 183 | 184 | uint32_t 185 | get_rand_uint32() 186 | { 187 | uint32_t val; 188 | int fd, ret; 189 | 190 | fd = open("/dev/urandom", O_RDONLY); 191 | if (fd < 0) pfatal("cannot open /dev/urandom"); 192 | 193 | ret = read(fd, &val, sizeof(uint32_t)); 194 | if (ret != sizeof(uint32_t)) { 195 | pfatal("error while reading from /dev/urandom"); 196 | } 197 | 198 | ret = close(fd); 199 | if (ret < 0) pfatal("error while closing /dev/urandom"); 200 | 201 | return val; 202 | } 203 | 204 | /* This utility opens the file pointed to by filename fn and tries to read 205 | in either the full contents of the file or up to *sz (or the full length 206 | of the file; whichever is less) if max is set to non-zero. It will return 207 | -1 in the case of an error. If succeeded *output will be set to a pointer 208 | to the buffer containing the contents of the file and *sz will be set to 209 | the total amount data read in. */ 210 | int 211 | read_full_file(const char * fn, unsigned char ** output, size_t * sz, int max) 212 | { 213 | FILE * fd; 214 | unsigned char * buf, * buf2; 215 | size_t alloc = 1024, total, read; 216 | int ret; 217 | 218 | if (!output) return -1; 219 | fd = fopen(fn, "r"); 220 | if (!fd) return -1; 221 | 222 | buf = malloc(alloc); 223 | if (!buf) return -1; 224 | 225 | total = 0; 226 | while (!feof(fd)) { 227 | read = max ? (*sz - total) : (alloc-total); 228 | if (read > (alloc-total)) read = alloc-total; 229 | read = fread(buf+total, 1, read, fd); 230 | if (ferror(fd)) goto err; 231 | total += read; 232 | if (feof(fd)) break; 233 | if (total == alloc) { 234 | alloc <<= 2; 235 | buf2 = realloc(buf, alloc); 236 | if (!buf2) goto err; 237 | buf = buf2; 238 | } 239 | if (max && !(*sz-total)) break; 240 | } 241 | 242 | ret = fclose(fd); 243 | if (ret < 0) goto err; 244 | 245 | *sz = total; 246 | *output = buf; 247 | return 0; 248 | err: 249 | free(buf); 250 | return -1; 251 | } 252 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | */ 20 | #ifndef UTILS_H 21 | #define UTILS_H 22 | 23 | void pfatal(const char *); 24 | void fatal(const char *); 25 | int get_raw_fd(); 26 | int get_iface_addrs(const char *, char **, char **, char **); 27 | int get_default_gw(char **, char **); 28 | uint32_t get_rand_uint32(); 29 | int read_full_file(const char *, unsigned char **, size_t *, int); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | const char * polarbearscan_version = "0.12"; 2 | --------------------------------------------------------------------------------