trafgen: udp: Do not use user-provided 'len' field to calculate csum
[netsniff-ng.git] / trafgen_l4.c
blob79c59146ed49d8eec64a9a6f5b7dbd4a92b9a03c
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Subject to the GPL, version 2.
4 */
6 #include <stdbool.h>
7 #include <netinet/in.h>
9 #include "die.h"
10 #include "csum.h"
11 #include "built_in.h"
12 #include "trafgen_l3.h"
13 #include "trafgen_l4.h"
14 #include "trafgen_conf.h"
15 #include "trafgen_proto.h"
17 static struct proto_field udp_fields[] = {
18 { .id = UDP_SPORT, .len = 2, .offset = 0 },
19 { .id = UDP_DPORT, .len = 2, .offset = 2 },
20 { .id = UDP_LEN, .len = 2, .offset = 4 },
21 { .id = UDP_CSUM, .len = 2, .offset = 6 },
24 static void udp_header_init(struct proto_hdr *hdr)
26 proto_lower_default_add(hdr, PROTO_IP4);
28 proto_header_fields_add(hdr, udp_fields, array_size(udp_fields));
31 static void udp_packet_finish(struct proto_hdr *hdr)
33 struct proto_hdr *lower = proto_lower_header(hdr);
34 struct packet *pkt = current_packet();
35 uint16_t total_len;
36 uint16_t csum;
38 total_len = pkt->len - hdr->pkt_offset;
39 proto_field_set_default_be16(hdr, UDP_LEN, total_len);
41 if (proto_field_is_set(hdr, UDP_CSUM))
42 return;
44 if (!lower)
45 return;
47 switch (lower->id) {
48 case PROTO_IP4:
49 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
50 total_len, IPPROTO_UDP);
51 break;
52 case PROTO_IP6:
53 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
54 total_len, IPPROTO_UDP);
55 break;
56 default:
57 csum = 0;
58 break;
61 proto_field_set_be16(hdr, UDP_CSUM, bswap_16(csum));
64 static struct proto_hdr udp_hdr = {
65 .id = PROTO_UDP,
66 .layer = PROTO_L4,
67 .header_init = udp_header_init,
68 .packet_finish = udp_packet_finish,
71 static struct proto_field tcp_fields[] = {
72 { .id = TCP_SPORT, .len = 2, .offset = 0 },
73 { .id = TCP_DPORT, .len = 2, .offset = 2 },
74 { .id = TCP_SEQ, .len = 4, .offset = 4 },
75 { .id = TCP_ACK_SEQ, .len = 4, .offset = 8 },
76 { .id = TCP_DOFF, .len = 2, .offset = 12, .shift = 12, .mask = 0xf000 },
77 /* reserved (4 bits) */
78 { .id = TCP_CWR, .len = 2, .offset = 12, .shift = 7, .mask = 0x0080 },
79 { .id = TCP_ECE, .len = 2, .offset = 12, .shift = 6, .mask = 0x0040 },
80 { .id = TCP_URG, .len = 2, .offset = 12, .shift = 5, .mask = 0x0020 },
81 { .id = TCP_ACK, .len = 2, .offset = 12, .shift = 4, .mask = 0x0010 },
82 { .id = TCP_PSH, .len = 2, .offset = 12, .shift = 3, .mask = 0x0008 },
83 { .id = TCP_RST, .len = 2, .offset = 12, .shift = 2, .mask = 0x0004 },
84 { .id = TCP_SYN, .len = 2, .offset = 12, .shift = 1, .mask = 0x0002 },
85 { .id = TCP_FIN, .len = 2, .offset = 12, .shift = 0, .mask = 0x0001 },
86 { .id = TCP_WINDOW, .len = 2, .offset = 14 },
87 { .id = TCP_CSUM, .len = 2, .offset = 16 },
88 { .id = TCP_URG_PTR, .len = 2, .offset = 18 },
91 static void tcp_header_init(struct proto_hdr *hdr)
93 proto_lower_default_add(hdr, PROTO_IP4);
95 proto_header_fields_add(hdr, tcp_fields, array_size(tcp_fields));
97 proto_field_set_default_be16(hdr, TCP_DOFF, 5);
100 static void tcp_packet_finish(struct proto_hdr *hdr)
102 struct proto_hdr *lower = proto_lower_header(hdr);
103 struct packet *pkt = current_packet();
104 uint16_t total_len;
105 uint16_t csum;
107 if (proto_field_is_set(hdr, TCP_CSUM))
108 return;
110 if (!lower)
111 return;
113 total_len = pkt->len - hdr->pkt_offset;
115 switch (lower->id) {
116 case PROTO_IP4:
117 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
118 total_len, IPPROTO_TCP);
119 break;
120 case PROTO_IP6:
121 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
122 total_len, IPPROTO_TCP);
123 break;
124 default:
125 csum = 0;
126 break;
129 proto_field_set_be16(hdr, TCP_CSUM, bswap_16(csum));
132 static struct proto_hdr tcp_hdr = {
133 .id = PROTO_TCP,
134 .layer = PROTO_L4,
135 .header_init = tcp_header_init,
136 .packet_finish = tcp_packet_finish,
139 static struct proto_field icmpv4_fields[] = {
140 { .id = ICMPV4_TYPE, .len = 1, .offset = 0 },
141 { .id = ICMPV4_CODE, .len = 1, .offset = 1 },
142 { .id = ICMPV4_CSUM, .len = 2, .offset = 2 },
143 /* Echo/Ping fields */
144 { .id = ICMPV4_ID, .len = 2, .offset = 4 },
145 { .id = ICMPV4_SEQ, .len = 2, .offset = 6 },
146 /* Redirect field */
147 { .id = ICMPV4_REDIR_ADDR, .len = 4, .offset = 4 },
148 /* Next-hop MTU */
149 { .id = ICMPV4_MTU, .len = 2, .offset = 6 },
152 static void icmpv4_header_init(struct proto_hdr *hdr)
154 proto_lower_default_add(hdr, PROTO_IP4);
156 proto_header_fields_add(hdr, icmpv4_fields, array_size(icmpv4_fields));
159 static void icmpv4_packet_finish(struct proto_hdr *hdr)
161 struct packet *pkt;
162 uint16_t csum;
164 if (proto_field_is_set(hdr, ICMPV4_CSUM))
165 return;
167 pkt = current_packet();
169 csum = htons(calc_csum(proto_header_ptr(hdr), pkt->len - hdr->pkt_offset));
170 proto_field_set_u16(hdr, ICMPV4_CSUM, bswap_16(csum));
173 static struct proto_hdr icmpv4_hdr = {
174 .id = PROTO_ICMP4,
175 .layer = PROTO_L4,
176 .header_init = icmpv4_header_init,
177 .packet_finish = icmpv4_packet_finish,
180 static struct proto_field icmpv6_fields[] = {
181 { .id = ICMPV6_TYPE, .len = 1, .offset = 0 },
182 { .id = ICMPV6_CODE, .len = 1, .offset = 1 },
183 { .id = ICMPV6_CSUM, .len = 2, .offset = 2 }
186 static void icmpv6_header_init(struct proto_hdr *hdr)
188 proto_lower_default_add(hdr, PROTO_IP6);
190 proto_header_fields_add(hdr, icmpv6_fields, array_size(icmpv6_fields));
193 static void icmpv6_packet_finish(struct proto_hdr *hdr)
195 struct proto_hdr *lower = proto_lower_header(hdr);
196 struct packet *pkt = current_packet();
197 uint16_t total_len;
198 uint16_t csum;
200 if (proto_field_is_set(hdr, ICMPV6_CSUM))
201 return;
203 if (!lower)
204 return;
206 total_len = pkt->len - hdr->pkt_offset;
208 switch (lower->id) {
209 case PROTO_IP6:
210 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
211 total_len, IPPROTO_ICMPV6);
212 break;
213 default:
214 csum = 0;
215 break;
218 proto_field_set_be16(hdr, ICMPV6_CSUM, bswap_16(csum));
221 static struct proto_hdr icmpv6_hdr = {
222 .id = PROTO_ICMP6,
223 .layer = PROTO_L4,
224 .header_init = icmpv6_header_init,
225 .packet_finish = icmpv6_packet_finish,
228 void protos_l4_init(void)
230 proto_header_register(&udp_hdr);
231 proto_header_register(&tcp_hdr);
232 proto_header_register(&icmpv4_hdr);
233 proto_header_register(&icmpv6_hdr);