trafgen: proto: Add ICMPv4 header generation
[netsniff-ng.git] / trafgen_l4.c
blobc109675969b978138aac6e2feb488d7594f2ebcf
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 total_len = proto_field_get_u16(hdr, UDP_LEN);
49 switch (lower->id) {
50 case PROTO_IP4:
51 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
52 total_len, IPPROTO_UDP);
53 break;
54 case PROTO_IP6:
55 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
56 total_len, IPPROTO_UDP);
57 break;
58 default:
59 csum = 0;
60 break;
63 proto_field_set_be16(hdr, UDP_CSUM, bswap_16(csum));
66 static struct proto_hdr udp_hdr = {
67 .id = PROTO_UDP,
68 .layer = PROTO_L4,
69 .header_init = udp_header_init,
70 .packet_finish = udp_packet_finish,
73 static struct proto_field tcp_fields[] = {
74 { .id = TCP_SPORT, .len = 2, .offset = 0 },
75 { .id = TCP_DPORT, .len = 2, .offset = 2 },
76 { .id = TCP_SEQ, .len = 4, .offset = 4 },
77 { .id = TCP_ACK_SEQ, .len = 4, .offset = 8 },
78 { .id = TCP_DOFF, .len = 2, .offset = 12, .shift = 12, .mask = 0xf000 },
79 /* reserved (4 bits) */
80 { .id = TCP_CWR, .len = 2, .offset = 12, .shift = 7, .mask = 0x0080 },
81 { .id = TCP_ECE, .len = 2, .offset = 12, .shift = 6, .mask = 0x0040 },
82 { .id = TCP_URG, .len = 2, .offset = 12, .shift = 5, .mask = 0x0020 },
83 { .id = TCP_ACK, .len = 2, .offset = 12, .shift = 4, .mask = 0x0010 },
84 { .id = TCP_PSH, .len = 2, .offset = 12, .shift = 3, .mask = 0x0008 },
85 { .id = TCP_RST, .len = 2, .offset = 12, .shift = 2, .mask = 0x0004 },
86 { .id = TCP_SYN, .len = 2, .offset = 12, .shift = 1, .mask = 0x0002 },
87 { .id = TCP_FIN, .len = 2, .offset = 12, .shift = 0, .mask = 0x0001 },
88 { .id = TCP_WINDOW, .len = 2, .offset = 14 },
89 { .id = TCP_CSUM, .len = 2, .offset = 16 },
90 { .id = TCP_URG_PTR, .len = 2, .offset = 18 },
93 static void tcp_header_init(struct proto_hdr *hdr)
95 proto_lower_default_add(hdr, PROTO_IP4);
97 proto_header_fields_add(hdr, tcp_fields, array_size(tcp_fields));
99 proto_field_set_default_be16(hdr, TCP_DOFF, 5);
102 static void tcp_packet_finish(struct proto_hdr *hdr)
104 struct proto_hdr *lower = proto_lower_header(hdr);
105 struct packet *pkt = current_packet();
106 uint16_t total_len;
107 uint16_t csum;
109 if (proto_field_is_set(hdr, TCP_CSUM))
110 return;
112 if (!lower)
113 return;
115 total_len = pkt->len - hdr->pkt_offset;
117 switch (lower->id) {
118 case PROTO_IP4:
119 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
120 total_len, IPPROTO_TCP);
121 break;
122 case PROTO_IP6:
123 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
124 total_len, IPPROTO_TCP);
125 break;
126 default:
127 csum = 0;
128 break;
131 proto_field_set_be16(hdr, TCP_CSUM, bswap_16(csum));
134 static struct proto_hdr tcp_hdr = {
135 .id = PROTO_TCP,
136 .layer = PROTO_L4,
137 .header_init = tcp_header_init,
138 .packet_finish = tcp_packet_finish,
141 static struct proto_field icmpv4_fields[] = {
142 { .id = ICMPV4_TYPE, .len = 1, .offset = 0 },
143 { .id = ICMPV4_CODE, .len = 1, .offset = 1 },
144 { .id = ICMPV4_CSUM, .len = 2, .offset = 2 },
145 /* Echo/Ping fields */
146 { .id = ICMPV4_ID, .len = 2, .offset = 4 },
147 { .id = ICMPV4_SEQ, .len = 2, .offset = 6 },
148 /* Redirect field */
149 { .id = ICMPV4_REDIR_ADDR, .len = 4, .offset = 4 },
150 /* Next-hop MTU */
151 { .id = ICMPV4_MTU, .len = 2, .offset = 6 },
154 static void icmpv4_header_init(struct proto_hdr *hdr)
156 proto_lower_default_add(hdr, PROTO_IP4);
158 proto_header_fields_add(hdr, icmpv4_fields, array_size(icmpv4_fields));
161 static void icmpv4_packet_finish(struct proto_hdr *hdr)
163 struct packet *pkt;
164 uint16_t csum;
166 if (proto_field_is_set(hdr, ICMPV4_CSUM))
167 return;
169 pkt = current_packet();
171 csum = htons(calc_csum(proto_header_ptr(hdr), pkt->len - hdr->pkt_offset));
172 proto_field_set_u16(hdr, ICMPV4_CSUM, bswap_16(csum));
175 static struct proto_hdr icmpv4_hdr = {
176 .id = PROTO_ICMP4,
177 .layer = PROTO_L4,
178 .header_init = icmpv4_header_init,
179 .packet_finish = icmpv4_packet_finish,
182 static struct proto_field icmpv6_fields[] = {
183 { .id = ICMPV6_TYPE, .len = 1, .offset = 0 },
184 { .id = ICMPV6_CODE, .len = 1, .offset = 1 },
185 { .id = ICMPV6_CSUM, .len = 2, .offset = 2 }
188 static void icmpv6_header_init(struct proto_hdr *hdr)
190 proto_lower_default_add(hdr, PROTO_IP6);
192 proto_header_fields_add(hdr, icmpv6_fields, array_size(icmpv6_fields));
195 static void icmpv6_packet_finish(struct proto_hdr *hdr)
197 struct proto_hdr *lower = proto_lower_header(hdr);
198 struct packet *pkt = current_packet();
199 uint16_t total_len;
200 uint16_t csum;
202 if (proto_field_is_set(hdr, ICMPV6_CSUM))
203 return;
205 if (!lower)
206 return;
208 total_len = pkt->len - hdr->pkt_offset;
210 switch (lower->id) {
211 case PROTO_IP6:
212 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
213 total_len, IPPROTO_ICMPV6);
214 break;
215 default:
216 csum = 0;
217 break;
220 proto_field_set_be16(hdr, ICMPV6_CSUM, bswap_16(csum));
223 static struct proto_hdr icmpv6_hdr = {
224 .id = PROTO_ICMP6,
225 .layer = PROTO_L4,
226 .header_init = icmpv6_header_init,
227 .packet_finish = icmpv6_packet_finish,
230 void protos_l4_init(void)
232 proto_header_register(&udp_hdr);
233 proto_header_register(&tcp_hdr);
234 proto_header_register(&icmpv4_hdr);
235 proto_header_register(&icmpv6_hdr);