How to inject new packets at higher layer?

Document created by cdnadmin on Jan 25, 2014
Version 1Show Document
  • View in full screen mode
This document was generated from CDN thread

Created by: Viktor S. Wold Eide on 31-01-2013 09:16:39 AM
I'm looking for a way to inject / send packets that have not been received from the platform, but rather been generated by a onep application itself. The onep_dpss_inject_raw_packet function seems to require layer 2 frames, which is rather low level. The  <a>onep_dpss_inject_packet</a> function seems to only deal with packets that have been received from the platform.
Is there a way to inject / send layer 3 (or layer 4) packets directly, without having to deal with layer 2 mac addresses, etc? If this is not supported in the current version, are there any plans for adding such functionality? Thanks.

Subject: RE: How to inject new packets at higher layer?
Replied by: Zach Seils on 04-02-2013 08:09:38 AM
Hi Viktor,

The answer to your question depends on location_id where you want to inject the packet.  For the ONEP_TARGET_LOCATION_HARDWARE_DEFINED_INPUT and ONEP_TARGET_LOCATION_HARDWARE_DEFINED_OUTPUT locations, the entire L2 frame is expected.  For the ONEP_TARGET_LOCATION_HARDWARE_DEFINED_PREROUTING location, you can just fill in the L3 information and leave the L2 information blank.

Regards,
Zach
 

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 07-02-2013 02:11:07 AM
Thanks a lot, Zach.

I assume that this is then the recommended way of injecting layer 3 packets, and maybe also the only way?

As mentioned, the onep_dpss_inject_packet function seems to deal only with packets initially received from the platform. Is that correct?

Related to packet injection is layer 3 packet construction and assembly. Are there any official or non-official recommendations for libraries to use in this respect?

Best regards
Viktor

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 07-02-2013 09:45:28 AM
No, you can inject brand new packets this way.  I have written a simple packet generator in onePK that relies on this function to inject new IPv4 datagrams (you are currently limited to IPv4 or IPv6).  I'm attaching my code as an example.  This uses Java JNI, but you should be able to see how to inject new frames.

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 07-02-2013 09:56:46 AM
To answer the other part of your question, we have requested some convenience functions to aid in packet construction, but in the mean time, my sample code builds these packets from scratch using the Linux struct definitions as a framework.

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 08-02-2013 04:56:30 AM
Thanks Joseph, for both the answer and the attached code.

The attached file seems to be an updated version of the one in the java PacketGenerator file posted earlier? From the code it seems that only the onep_dpss_inject_raw_packet function is used, and not the onep_dpss_inject_packet function?

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 08-02-2013 05:24:02 AM
That's good to hear, Joseph. So far we've used c code for testing, since the dpss part of onePK is not officially available from Java, as far as we know. We have looked at different libraries for packet construction and assembly, including libnet which we have tested in combination with onePK. Information about supported or recommended libraries is highly beneficial, in particular as long as this functionality is not available from onePK itself.
Updates regarding the dpss for Java is also interesting.

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 08-02-2013 08:34:10 AM
Right.  The inject_packet function can only be used when you have an existing packet structure.  Since this is an opaque structure, you cannot build it yourself.  Therefore you have to rely on things like the DPSS callback flow to provide it.  We've requested APIs to be able to build a packet structure, but they do not exist yet.  In lieu of that, you can construct the packet youself and inject it using onep_dpss_inject_raw_packet().  The functionality is the same.  That is, a new packet is placed on the wire.  If you do not need to build your own L2 headers, then you can stick with the PREROUTING flag.  Else you can use OUTPUT and build the entire frame.
 
Also note, I've said it before but only IPv4 and IPv6 packets are supported.  If you try to send any other type of frame the DPSS will reject it.

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 08-02-2013 08:36:12 AM
Agreed all around.  Currently we don't have APIs within onePK to do convenient packet creation, but we have requested them.  I haven't personally used any other libraries to do this.  What was your experience with libnet?  I'm familiar with it, but I haven't looked to see if it can provide a simple byte buffer for use with the raw inject function.

Java support for DPSS is another oft-requested feature.  Unfortunately, we don't have an update on when that could be made available.

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 08-02-2013 09:03:45 AM
We've done some initial testing using onePK together with libnet and so far it looks fine. The generated packets, e.g., UDP over IP over Ethernet seem to be correctly injected by the router. As you point out, it is necessary to get access to the byte buffer with the libnet constructed frame/packet in order to use the raw inject function. This can be done with the libnet_adv_cull_packet function. Note that you need to initialize the libnet_init with LIBNET_LINK_ADV to use this function.

Best regards
Viktor

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 08-02-2013 09:05:32 AM
Thanks for the pointer.  It's good to know there's an alternative to packing bytes manually.

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 11-02-2013 02:16:49 AM
Good to hear that it might be useful, Joseph. We certainly would like to hear about experiences or recommendations from other people in this respect.

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 11-02-2013 01:55:26 PM
Next time someone asks about this, I'll be able to recommend it.  I'm going to play with libnet some myself so I can feel more comfortable with it.

Subject: RE: How to inject new packets at higher layer?
Replied by: Viktor S. Wold Eide on 12-02-2013 07:44:00 AM
We have quite limited experience with using libnet with onePK so far. Still, it might be worthwhile for others to have a look at it. Hopefully, they will also provide some feedback on the experience.

Subject: RE: How to inject new packets at higher layer?
Replied by: Joseph Clarke on 22-10-2013 11:06:53 PM
For another project I just completed, I decided to give libnet a spin.  I like it.  It made packet generation much easier.  Here's a snippet of code that builds a TCP ACK packet from the ground up, culls it, and then injects it on the output interface.
 1            libnet_ptag_t etht, ipt, tcpt;
 2            char errbuf[LIBNET_ERRBUF_SIZE];
 3 
 4            lctx = libnet_init(LIBNET_LINK_ADV, NULL, errbuf);
 5            if (lctx == NULL) {
 6                fprintf(stderr, "ERROR: Failed to initialize libnet: %s\n", errbuf);
 7                goto cleanup;
 8            }
 9            
10            tcpt = libnet_build_tcp((uint16_t) dstPort, (uint16_t) srcPort,
11                                    ntohl(l4tcp->ack_seq), ntohl(l4tcp->seq) + psize,
12                                    TH_ACK, ntohs(l4tcp->window), 0,
13                                    ntohs(l4tcp->urg_ptr), LIBNET_TCP_H, NULL, 0, lctx, 0);
14            if (tcpt == -1) {
15                fprintf(stderr, "ERROR: Failed to generate TCP header: %s\n", libnet_geterror(lctx));
16                goto cleanup;
17            }
18            
19            ipt = libnet_build_ipv4(LIBNET_TCP_H + LIBNET_IPV4_H, iph->tos,
20                                    libnet_get_prand(LIBNET_PRu16), 0, 64,
21                                    IPPROTO_TCP, 0, iph->daddr,
22                                    iph->saddr, NULL, 0, lctx, 0);
23            if (ipt == -1) {
24                fprintf(stderr, "ERROR: Failed to generate IPv4 header: %s\n", libnet_geterror(lctx));
25                goto cleanup;
26            }
27            
28            etht = libnet_build_ethernet(eh->ether_shost, eh->ether_dhost,
29                                         ETHERTYPE_IP, NULL, 0, lctx, 0);
30            if (etht == -1) {
31                fprintf(stderr, "ERROR: Failed to generate ethernet header: %s\n", libnet_geterror(lctx));
32                goto cleanup;
33            }
34            
35            if (libnet_adv_cull_packet(lctx, &rbuf, &nlen) == -1) {
36                fprintf(stderr, "ERROR: Failed to get packet buffer: %s\n", libnet_geterror(lctx));
37                goto cleanup;
38            }
39            
40            printf("INFO: Sending ACK on %s\n", ifname);
41            
42            rc = onep_dpss_inject_raw_packet(ne1, rbuf, nlen, 0, intf, ONEP_TARGET_LOCATION_HARDWARE_DEFINED_OUTPUT);
43            if (rc != ONEP_OK) {
44                fprintf(stderr, "ERROR: Failed to generate ACK back to client: %s (%d)\n", onep_strerror(rc), rc);
45                goto cleanup;
46            }

Attachments

    Outcomes