Commit ef740130 authored by Stig Venaas's avatar Stig Venaas
Browse files

add packet size checks, fixed so don't look for udp/tcp header in non-initial...

add packet size checks, fixed so don't look for udp/tcp header in non-initial fragments, setting udp ports to host byte order, support for IPv6 udp/tcp, and IPv6 fragment id/offset

git-svn-id: file:///home/svn/mapi/trunk@828 8d5bb341-7cf1-0310-8cf6-ba355fef3186
parent 87bca627
......@@ -64,30 +64,75 @@ static int topx_reset(mapidflib_function_instance_t *instance)
return 0;
}
void extract_field(struct topx_field *field, unsigned char *ip_pkt, int protocol, int pfield);
void extract_field(struct topx_field *field, unsigned char *ip_pkt, size_t length, int protocol, int pfield);
struct topx_hash_node *hash_lookup(struct topx_val *value, struct topx_data *data);
void check_for_shift(struct topx_data *data,struct topx_list_node *node);
void add_to_hashtable_and_list(struct topx_data *data, struct topx_val *value, unsigned long long bytes, unsigned int last_rst);
void add_field_to_list(struct topx_field *field,struct topx_data *data,unsigned long long bytes,unsigned int last_rst);
void extract_field(struct topx_field *field, unsigned char *ip_pkt, int protocol, int pfield) {
/* returns NULL on error */
static unsigned char *find_hdrs(unsigned char *type, unsigned char *fragoff0, unsigned char wanted, unsigned char *ip6_pkt, size_t length) {
unsigned char *p;
struct ip6_frag *frag;
if (sizeof(struct ip6_hdr) > length)
return NULL;
*fragoff0 = 1;
*type = ((struct ip6_hdr *)ip6_pkt)->ip6_nxt;
p = ip6_pkt + sizeof(struct ip6_hdr);
for (;;) {
if (*type == wanted)
return p;
switch (*type) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
if (p + 8 > ip6_pkt + length) /* option is at least 8 long */
return NULL;
*type = *p++;
p += 7 + 8 * *p; /* 7 bytes + 8 * len bytes */
break;
case IPPROTO_FRAGMENT:
frag = (struct ip6_frag *)p;
if (p + 8 > ip6_pkt + length) /* option is 8 bytes long */
return NULL;
*fragoff0 = (frag->ip6f_offlg & IP6F_OFF_MASK) ? 0 : 1;
*type = frag->ip6f_nxt;
p += 8;
break;
default:
return p;
}
}
}
void extract_field(struct topx_field *field, unsigned char *ip_pkt, size_t length, int protocol, int pfield) {
ip_header* ip;
struct ip6_hdr *ip6;
uint8_t ip_ver;
int ip_len;
unsigned char next, fragoff0;
struct ip6_frag *frag6;
tcp_header* tcp;
udp_header* udp;
field->len = 0;
if (length < sizeof(ip_header))
return;
ip = (ip_header *)ip_pkt;
ip_ver = ip->ver_ihl >> 4;
if (ip_ver == 4)
ip_len = (ip->ver_ihl & 0xf) * 4;
else if (ip_ver == 6)
else if (ip_ver == 6) {
ip6 = (struct ip6_hdr *)ip_pkt;
else
if (length < sizeof(struct ip6_hdr))
return;
} else
return; /* Only support versions 4 and 6 */
field->needs_reverse=0;
......@@ -117,12 +162,37 @@ void extract_field(struct topx_field *field, unsigned char *ip_pkt, int protocol
field->len=2;
break;
case TOPX_IP_ID:
field->pointer=&(ip->id);
field->len=2;
if (ip_ver == 4) {
field->pointer = &ip->id;
field->needs_reverse = 1;
field->len = 2;
} else {
frag6 = (struct ip6_frag *)find_hdrs(&next, &fragoff0, IPPROTO_FRAGMENT, ip_pkt, length);
if (frag6 && next == IPPROTO_FRAGMENT && (unsigned char *)frag6 + sizeof(struct ip6_frag) <= ip_pkt + length) {
field->pointer = &frag6->ip6f_ident;
field->needs_reverse = 1;
} else {
field->value = 0;
field->pointer = &field->value;
}
field->len = 4;
}
break;
case TOPX_IP_OFFSET:
field->pointer=&(ip->off);
field->len=2;
if (ip_ver == 4) {
field->pointer = &ip->off;
field->needs_reverse = 1;
} else {
frag6 = (struct ip6_frag *)find_hdrs(&next, &fragoff0, IPPROTO_FRAGMENT, ip_pkt, length);
if (frag6 && next == IPPROTO_FRAGMENT && (unsigned char *)frag6 + sizeof(struct ip6_frag) <= ip_pkt + length) {
field->pointer = &frag6->ip6f_offlg;
field->needs_reverse = 1;
} else {
field->value = 0;
field->pointer = &field->value;
}
}
field->len = 2;
break;
case TOPX_IP_TTL:
field->pointer = (ip_ver == 4) ? &ip->ttl : &ip6->ip6_hlim;
......@@ -162,9 +232,18 @@ void extract_field(struct topx_field *field, unsigned char *ip_pkt, int protocol
}
break;
case TOPX_TCP:
if (ip->ptcl != IPPROTO_TCP) /* no TCP packet */
return;
tcp = (tcp_header*)(ip_pkt + ip_len);
if (ip_ver == 4) {
if (ip->ptcl != IPPROTO_TCP || ntohs(ip->off) & 0x1fff) /* no TCP packet or no TCP header */
return;
tcp = (tcp_header *)(ip_pkt + ip_len);
} else { /* IPv6 */
tcp = (tcp_header *)find_hdrs(&next, &fragoff0, IPPROTO_TCP, ip_pkt, length);
if (!tcp || next != IPPROTO_TCP || !fragoff0)
return;
}
if ((unsigned char *)tcp + sizeof(tcp_header) > ip_pkt + length)
return; /* Not room for tcp header in packet */
//tcp_len = tcp->off * 4;
switch(pfield) {
case TOPX_TCP_SRCPORT:
......@@ -204,15 +283,26 @@ void extract_field(struct topx_field *field, unsigned char *ip_pkt, int protocol
}
break;
case TOPX_UDP:
if (ip->ptcl != IPPROTO_UDP) /* no UDP packet */
return;
udp = (udp_header *)(ip_pkt + ip_len);
if (ip_ver == 4) {
if (ip->ptcl != IPPROTO_UDP || ntohs(ip->off) & 0x1fff) /* no UDP packet or no UDP header */
return;
udp = (udp_header *)(ip_pkt + ip_len);
} else { /* IPv6 */
udp = (udp_header *)find_hdrs(&next, &fragoff0, IPPROTO_UDP, ip_pkt, length);
if (!udp || next != IPPROTO_UDP || !fragoff0)
return;
}
if ((unsigned char *)udp + sizeof(udp_header) > ip_pkt + length)
return; /* Not room for udp header in packet */
switch(pfield) {
case TOPX_UDP_SRCPORT:
field->needs_reverse=1;
field->pointer=&(udp->sport);
field->len=2;
break;
case TOPX_UDP_DSTPORT:
field->needs_reverse=1;
field->pointer=&(udp->dport);
field->len=2;
break;
......@@ -393,7 +483,7 @@ static int topx_process(mapidflib_function_instance_t *instance,
assert(0);
}
extract_field(&field, packet + ether_len, data->protocol, data->field);
extract_field(&field, packet + ether_len, pkt_head->wlen - ether_len, data->protocol, data->field);
if(field.len==0)
return 1;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment