pkt_gen.cpp revision fa8792d5
1/*
2  Ido Barnea
3  Cisco Systems, Inc.
4*/
5
6/*
7  Copyright (c) 2016-2017 Cisco Systems, Inc.
8
9  Licensed under the Apache License, Version 2.0 (the "License");
10  you may not use this file except in compliance with the License.
11  You may obtain a copy of the License at
12
13  http://www.apache.org/licenses/LICENSE-2.0
14
15  Unless required by applicable law or agreed to in writing, software
16  distributed under the License is distributed on an "AS IS" BASIS,
17  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  See the License for the specific language governing permissions and
19  limitations under the License.
20*/
21
22#include <assert.h>
23#include <netinet/in.h>
24#include <common/Network/Packet/TcpHeader.h>
25#include <common/Network/Packet/UdpHeader.h>
26#include <common/Network/Packet/IcmpHeader.h>
27#include <common/Network/Packet/IPHeader.h>
28#include <common/Network/Packet/IPv6Header.h>
29#include <common/Network/Packet/EthernetHeader.h>
30#include <common/Network/Packet/Arp.h>
31#include "rx_check_header.h"
32#include "pkt_gen.h"
33#include "bp_sim.h"
34// For use in tests
35char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags
36                                   , uint16_t max_payload, int &pkt_size) {
37    // ASA 2
38    uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25};
39    uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02};
40    uint8_t vlan_header[4] = {0x0a, 0xbc, 0x00, 0x00}; // we set the type below according to if pkt is ipv4 or 6
41    uint8_t vlan_header2[4] = {0x0a, 0xbc, 0x88, 0xa8};
42    uint16_t l2_proto;
43    uint16_t payload_len;
44
45    // ASA 1
46    //        uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b};
47    //      uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0};
48    if (flags & (DPF_VLAN | DPF_QINQ)) {
49        if (flags & DPF_QINQ) {
50            l2_proto = htons(EthernetHeader::Protocol::QINQ);
51        } else {
52            l2_proto = htons(EthernetHeader::Protocol::VLAN);
53        }
54    } else {
55        l2_proto = htons(l3_type);
56    }
57
58    uint8_t ip_header[] = {
59        0x45,0x03,0x00,0x30,
60        0x00,0x00,0x40,0x00,
61        0xff,0x01,0xbd,0x04,
62        0x10,0x0,0x0,0x1, //SIP
63        0x30,0x0,0x0,0x1, //DIP
64        //                      0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it.
65    };
66    uint8_t ipv6_header[] = {
67        0x60,0x10,0xff,0x30, // traffic class + flow label
68        0x00,0x00,0x40,0x00, // payload len + next header + hop limit
69        0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP
70        0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP
71    };
72    uint8_t udp_header[] =  {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00};
73    uint8_t udp_data[] = {0x64,0x31,0x3a,0x61,
74                          0x64,0x32,0x3a,0x69,0x64,
75                          0x32,0x30,0x3a,0xd0,0x0e,
76                          0xa1,0x4b,0x7b,0xbd,0xbd,
77                          0x16,0xc6,0xdb,0xc4,0xbb,0x43,
78                          0xf9,0x4b,0x51,0x68,0x33,0x72,
79                          0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f,
80                          0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3,
81                          0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f,
82                          0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39,
83                          0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31,
84                          0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d,
85                          0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d,
86                          0xe7
87    };
88
89    uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports
90                            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num
91                            0x50, 0x00, 0xff, 0xff, // Header size, flags, window size
92                            0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer
93    };
94
95    uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5,
96                          0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5};
97
98    uint8_t icmp_header[] = {
99        0x08, 0x00,
100        0xb8, 0x21,  //checksum
101        0xaa, 0xbb,  // id
102        0x00, 0x01,  // Sequence number
103    };
104    uint8_t icmp_data[] = {
105        0xd6, 0x6e, 0x64, 0x34, // magic
106        0x6a, 0xad, 0x0f, 0x00, //64 bit counter
107        0x00, 0x56, 0x34, 0x12,
108        0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq
109    };
110
111    pkt_size = 14;
112
113    if (flags & (DPF_VLAN | DPF_QINQ)) {
114        pkt_size += 4;
115        if (flags & DPF_QINQ) {
116            pkt_size += 4;
117        }
118    }
119
120    switch(l3_type) {
121    case EthernetHeader::Protocol::IP:
122        pkt_size += sizeof(ip_header);
123        break;
124    case EthernetHeader::Protocol::IPv6:
125        pkt_size += sizeof(ipv6_header);
126        if (flags & DPF_RXCHECK) {
127            pkt_size += sizeof(struct CRx_check_header);
128        }
129        break;
130    case EthernetHeader::Protocol::ARP:
131        pkt_size += sizeof(ArpHdr);
132        break;
133    }
134
135    switch (l4_proto) {
136    case IPPROTO_ICMP:
137        pkt_size += sizeof(icmp_header);
138        payload_len = (max_payload < sizeof(icmp_data)) ? max_payload:sizeof(icmp_data);
139        pkt_size += payload_len;
140        break;
141    case IPPROTO_UDP:
142        pkt_size += sizeof(udp_header);
143        payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data);
144        pkt_size += payload_len;
145        break;
146    case IPPROTO_TCP:
147        pkt_size += sizeof(tcp_header);
148        payload_len = (max_payload < sizeof(tcp_data)) ? max_payload:sizeof(tcp_data);
149        pkt_size += payload_len;
150        break;
151    default:
152        payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data);
153        pkt_size += payload_len;
154        break;
155    }
156
157    char *p_start = (char *)malloc(pkt_size);
158    assert(p_start);
159    char *p = p_start;
160
161    /* set pkt data */
162    memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac);
163    memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac);
164    memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto);
165
166    if (flags & (DPF_VLAN | DPF_QINQ)) {
167        if (flags & DPF_QINQ) {
168            uint16_t vlan_type = htons(EthernetHeader::Protocol::VLAN);
169            memcpy(&vlan_header2[2], &vlan_type, sizeof(vlan_type));
170            memcpy(p, &vlan_header2, sizeof(vlan_header2)); p += sizeof(vlan_header2);
171        }
172
173        uint16_t l3_type_htons = htons(l3_type);
174        memcpy(&vlan_header[2], &l3_type_htons, sizeof(l3_type));
175        memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header);
176    }
177
178    struct IPHeader *ip = (IPHeader *)p;
179    struct IPv6Header *ipv6 = (IPv6Header *)p;
180    switch(l3_type) {
181    case EthernetHeader::Protocol::IP:
182        memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header);
183        ip->setProtocol(l4_proto);
184        ip->setTotalLength(pkt_size - 14);
185        ip->setId(ip_id);
186        break;
187    case EthernetHeader::Protocol::IPv6:
188        memcpy(p, ipv6_header, sizeof(ipv6_header)); p += sizeof(ipv6_header);
189        if (flags & DPF_RXCHECK) {
190            // rx check header
191            ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE);
192            if (flags & DPF_RXCHECK) {
193                struct CRx_check_header *rxch = (struct CRx_check_header *)p;
194                p += sizeof(CRx_check_header);
195                rxch->m_option_type = l4_proto;
196                rxch->m_option_len = RX_CHECK_V6_OPT_LEN;
197            }
198        } else {
199            ipv6->setNextHdr(l4_proto);
200        }
201        ipv6->setPayloadLen(pkt_size - 14 - sizeof(ipv6_header));
202        ipv6->setFlowLabel(ip_id);
203        break;
204    case EthernetHeader::Protocol::ARP:
205        uint16_t vlan = (flags & DPF_VLAN) ? 200 : 0;
206        create_arp_req((uint8_t *)p_start, 0x01020304, 0x05060708, src_mac, vlan, 0);
207        return p_start;
208        break;
209    }
210
211    struct TCPHeader *tcp = (TCPHeader *)p;
212    struct ICMPHeader *icmp= (ICMPHeader *)p;
213    switch (l4_proto) {
214    case IPPROTO_ICMP:
215        memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header);
216        memcpy(p, icmp_data, payload_len); p += payload_len;
217        icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data));
218        break;
219    case IPPROTO_UDP:
220        memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header);
221        memcpy(p, udp_data, payload_len); p += payload_len;
222        break;
223    case IPPROTO_TCP:
224        memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header);
225        memcpy(p, tcp_data, payload_len); p += payload_len;
226        tcp->setSynFlag(false);
227        // printf("Sending TCP header:");
228        //tcp->dump(stdout);
229        break;
230    default:
231        memcpy(p, udp_data, payload_len); p += payload_len;
232        break;
233    }
234
235    switch(l3_type) {
236    case EthernetHeader::Protocol::IP:
237        ip->setTimeToLive(ttl);
238        if (flags & DPF_TOS_1) {
239            ip->setTOS(TOS_TTL_RESERVE_DUPLICATE);
240        }else{
241            ip->setTOS(0x2);
242        }
243
244        ip->updateCheckSum();
245        break;
246    case EthernetHeader::Protocol::IPv6:
247        ipv6->setHopLimit(ttl);
248        if (flags & DPF_TOS_1) {
249            ipv6->setTrafficClass(TOS_TTL_RESERVE_DUPLICATE);
250        }else{
251            ipv6->setTrafficClass(0x2);
252        }
253
254        break;
255    }
256
257    return p_start;
258}
259
260/*
261 * Create ARP request packet
262 * Parameters:
263 *  pkt - Buffer to fill the packet in. Size should be big enough to contain the packet (60 is a good value).
264 *  sip - Our source IP
265 *  tip - Target IP for which we need resolution (In case of gratuitous ARP, should be equal sip).
266 *  src_mac - Our source MAC
267 *  vlan - VLAN tag to send the packet on. If set to 0, no vlan will be sent.
268 *  port - Port we intended to send packet on. This is needed since we put some "magic" number with the port, so
269 *         we can identify if we are connected in loopback, which ports are connected.
270 */
271void CTestPktGen::create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan
272                                 , uint16_t port) {
273    uint16_t l2_proto = htons(EthernetHeader::Protocol::ARP);
274
275    // dst MAC
276    memset(pkt, 0xff, ETHER_ADDR_LEN);
277    pkt += ETHER_ADDR_LEN;
278    // src MAC
279    memcpy(pkt, src_mac, ETHER_ADDR_LEN);
280    pkt += ETHER_ADDR_LEN;
281
282    if (vlan != 0) {
283        uint16_t htons_vlan = htons(vlan);
284        uint16_t vlan_proto = htons(0x8100);
285        memcpy(pkt, &vlan_proto, sizeof(vlan_proto));
286        pkt += 2;
287        memcpy(pkt, &htons_vlan, sizeof(uint16_t));
288        pkt += 2;
289    }
290
291    // l3 type
292    memcpy(pkt, &l2_proto, sizeof(l2_proto));
293    pkt += 2;
294
295    ArpHdr *arp = (ArpHdr *)pkt;
296    arp->m_arp_hrd = htons(ArpHdr::ARP_HDR_HRD_ETHER); // Format of hardware address
297    arp->m_arp_pro = htons(EthernetHeader::Protocol::IP); // Format of protocol address
298    arp->m_arp_hln = ETHER_ADDR_LEN; // Length of hardware address
299    arp->m_arp_pln = 4; // Length of protocol address
300    arp->m_arp_op = htons(ArpHdr::ARP_HDR_OP_REQUEST); // ARP opcode (command)
301
302    memcpy(&arp->m_arp_sha.data, src_mac, ETHER_ADDR_LEN); // Sender MAC address
303    arp->m_arp_sip = htonl(sip); // Sender IP address
304
305    uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
306    memcpy(&arp->m_arp_tha.data, magic, 5); // Target MAC address
307    arp->m_arp_tha.data[5] = port;
308    arp->m_arp_tip = htonl(tip);
309}
310