| @@ -205,15 +205,6 @@ int dhcp_check(struct nfq_data *nfa, dp_conf *conf) { | |||
| if ( conf->debug ) printf("got a packet, len = %i\n", pktlen); | |||
| /* a bit too much ;) | |||
| if ( conf->debug ) { | |||
| for(i=0; i<pktlen; i++) { | |||
| if ( !(i%16) ) printf("\n"); | |||
| printf("%02x ", pkt[i]); | |||
| } | |||
| } | |||
| */ | |||
| // can we read the IP proto and IP header length ? | |||
| if ( pktlen > 0 ) { | |||
| ipver = pkt[offset]; | |||
| @@ -221,25 +212,89 @@ int dhcp_check(struct nfq_data *nfa, dp_conf *conf) { | |||
| ihl = pkt[offset]; | |||
| ihl &= 0x0f; | |||
| if ( ipver != 4 ) { | |||
| if ( ipver == 4 ) { | |||
| // jump to DHCPv4 | |||
| offset += ( ihl * 4 ) + 8; | |||
| dhcpv4_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen); | |||
| } | |||
| else if ( ipver == 6 ) { | |||
| // jump to DHCPv6 | |||
| offset += 48 + 8; | |||
| dhcpv6_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen); | |||
| } | |||
| else { | |||
| if ( conf->debug ) printf("not an IPv4 packet\n"); | |||
| rv = NF_ACCEPT; | |||
| goto end; | |||
| } | |||
| } | |||
| // jump over the IPv4 header | |||
| offset += ihl * 4; | |||
| if ( remoteidlen>0 ) { | |||
| // count the packet, even when blacklisted. | |||
| dp_accounting_add(conf, remoteid, remoteidlen); | |||
| // check if already in the blacklist | |||
| if ( dp_blacklist_check(conf, remoteid, remoteidlen) == NF_DROP ) | |||
| rv = NF_DROP; | |||
| // check if it must be added to the blacklist | |||
| else if ( dp_accounting_check(conf, remoteid, remoteidlen) == NF_DROP ) { | |||
| dp_blacklist_add(conf, remoteid, remoteidlen); | |||
| rv = NF_DROP; | |||
| } | |||
| } | |||
| end: | |||
| dp_hash_cleanup(conf); | |||
| // jump over UDP + DHCP header | |||
| offset += 8 + 28 + 16 + 64 + 128; | |||
| return rv; | |||
| } | |||
| void dhcpv6_check(dp_conf *conf, unsigned char *pkt, int pktlen, int offset, unsigned char *remoteid, int *remoteidlen) { | |||
| while(offset<pktlen) { | |||
| uint8_t msgtype = (uint8_t)pkt[offset]; | |||
| switch(msgtype) { | |||
| case 11: // RELAY-FORW | |||
| case 12: // RELAY-REPL | |||
| offset += 2 + 16 + 16; // msg-type, hop-count, link-addr, peer-addr | |||
| break; | |||
| default: // all other msgtypes | |||
| offset += 2; // msg-type, hop-count | |||
| } | |||
| while(offset+1<pktlen) { | |||
| uint8_t code = (uint8_t)pkt[offset]; | |||
| uint8_t len = (uint8_t)pkt[offset+1]; | |||
| offset+2; | |||
| if ( code == 1 ) { // Client identifier / DUID | |||
| remoteid = pkt+offset; | |||
| *remoteidlen = len; | |||
| break; | |||
| } | |||
| offset+=len; | |||
| } | |||
| if ( *remoteidlen>0 ) | |||
| break; | |||
| } | |||
| } | |||
| void dhcpv4_check(dp_conf *conf, unsigned char *pkt, int pktlen, int offset, unsigned char *remoteid, int *remoteidlen) { | |||
| int hwaddrpos = offset + 28; // remember where the hw addr is if we need to fallback to it | |||
| int hwlenpos = offset + 2; // remember where the hw addr len is if we need to fallback to it | |||
| // jump DHCP header | |||
| offset += 28 + 16 + 64 + 128; | |||
| // minimum packet size, fixed header + magic cookie (4 octets) | |||
| if ( pktlen < offset + 4 ) { | |||
| if ( conf->debug ) printf("packet too small\n"); | |||
| rv = NF_ACCEPT; | |||
| goto end; | |||
| return; | |||
| } | |||
| // check magic cookie | |||
| @@ -249,9 +304,7 @@ int dhcp_check(struct nfq_data *nfa, dp_conf *conf) { | |||
| "invalid magic cookie %02x%02x%02x%02x\n", | |||
| pkt[offset], pkt[offset+1], | |||
| pkt[offset+2], pkt[offset+3]); | |||
| rv = NF_ACCEPT; | |||
| goto end; | |||
| return; | |||
| } | |||
| offset+=4; | |||
| @@ -301,13 +354,11 @@ int dhcp_check(struct nfq_data *nfa, dp_conf *conf) { | |||
| // make sure we don't overflow and can read all data | |||
| if ( o82off + olen > len ) { | |||
| if ( conf->debug) printf("option 82.2 data too long\n"); | |||
| rv = NF_ACCEPT; | |||
| goto end; | |||
| break; | |||
| } | |||
| else { | |||
| remoteid = o82 + o82off; | |||
| remoteidlen = olen; | |||
| found=1; | |||
| *remoteidlen = olen; | |||
| } | |||
| } | |||
| @@ -318,26 +369,14 @@ int dhcp_check(struct nfq_data *nfa, dp_conf *conf) { | |||
| offset+=len; | |||
| } | |||
| if ( found ) { | |||
| // count the packet, even when blacklisted. | |||
| dp_accounting_add(conf, remoteid, remoteidlen); | |||
| // check if already in the blacklist | |||
| if ( dp_blacklist_check(conf, remoteid, remoteidlen) == NF_DROP ) | |||
| rv = NF_DROP; | |||
| // check if it must be added to the blacklist | |||
| else if ( dp_accounting_check(conf, remoteid, remoteidlen) == NF_DROP ) { | |||
| dp_blacklist_add(conf, remoteid, remoteidlen); | |||
| rv = NF_DROP; | |||
| // if we didn't find opt82.2, we fallback to the hw addr | |||
| if ( *remoteidlen == 0 ) { | |||
| // nope, we won't overflow | |||
| if ( (uint8_t)pkt[hwlenpos] <= 16 ) { | |||
| remoteid = pkt+hwaddrpos; | |||
| remoteidlen = (uint8_t)pkt[hwlenpos]; | |||
| } | |||
| } | |||
| end: | |||
| dp_hash_cleanup(conf); | |||
| return rv; | |||
| } | |||
| // netfilter queue callback | |||