File: getpayloaddemo.c

package info (click to toggle)
libtrace3 3.0.22-0.2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,452 kB
  • sloc: ansic: 24,574; sh: 11,372; cpp: 1,811; makefile: 460; yacc: 96; lex: 50
file content (176 lines) | stat: -rw-r--r-- 4,958 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* Trivial libtrace program that prints the fields in the header for all
 * UDP packets in a trace. Instead of using trace_get_transport, we're going
 * to jump to the IP layer and use trace_get_payload_from_ip to find the UDP
 * header.
 *
 * Designed to demonstrate the use of trace_get_payload_from_X functions
 */
#include "libtrace.h"
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
#include <getopt.h>
#include <arpa/inet.h>

static void per_packet(libtrace_packet_t *packet)
{
	uint8_t proto;
	uint16_t ethertype;
	uint32_t rem;
	void *ltheader = NULL;
	libtrace_udp_t *udp = NULL;
	libtrace_ip_t *ip = NULL;
	libtrace_ip6_t *ip6 = NULL;

	/* OK, this is slightly tricky so pay attention.
	 * 
	 * ethertype and rem are used as 'output' parameters here. What this
	 * means is that their current values are ignored by the function
	 * but they are updated to contain the protocol and amount of 
	 * payload remaining for the header that is being returned.
	 * 
	 * We need to pass in the address of both these parameters, so
	 * that they can be modified by the function. This is why there
	 * is an '&' before both parameters.
	 */
	ltheader = trace_get_layer3(packet, &ethertype, &rem);

	/* If there was no layer 3 header, ignore the packet */
	if (ltheader == NULL)
		return;

	/* If there is no packet remaining, there is no point in going any
	 * further */
	if (rem == 0)
		return;

	/* Ok, we've got a layer 3 header - let's cast it to the appropriate
	 * type and use the appropriate get_payload function to find the next
	 * header. 
	 *
	 */
	if (ethertype == TRACE_ETHERTYPE_IP) {
		/* Our layer 3 header is IPv4 */
		
		/* Cast the returned header to a libtrace_ip_t */
		ip = (libtrace_ip_t *)ltheader;

		/* Use the get_payload_from_ip function to skip past the IPv4
		 * header. The key thing here is that rem needs to contain
		 * the same value that resulted from the earlier call to
		 * trace_get_layer3 */

		ltheader = trace_get_payload_from_ip(ip, &proto, &rem);

	} else if (ethertype == TRACE_ETHERTYPE_IPV6) {
		/* Our layer 3 header is IPv6 */
		
		/* Cast the returned header to a libtrace_ip6_t */
		ip6 = (libtrace_ip6_t *)ltheader;

		/* Use the get_payload_from_ip6 function to skip past the IPv6
		 * header. The key thing here is that rem needs to contain
		 * the same value that resulted from the earlier call to
		 * trace_get_layer3 */

		ltheader = trace_get_payload_from_ip6(ip6, &proto, &rem);

	} else {
		/* Let's ignore any other Layer 3 headers for now */
		return;
	}

	/* Check if there was a header present after the layer 3 header. */
	if (ltheader == NULL)
		return;

	/* Check if the protocol is UDP, using the defined value for UDP 
	 * that is defined in libtrace.h (search for libtrace_ipproto_t for
	 * a full list) */
	if (proto != TRACE_IPPROTO_UDP)
		return;

	/* One last check - make sure we have a full UDP header before 
	 * trying to grab fields out of it. */
	if (rem < sizeof(libtrace_udp_t))
		return;

	/* Now, cast the returned header to the appropriate header type */
	udp = (libtrace_udp_t *)ltheader;

	/* Dump each field to standard output. Be careful to byteswap any
	 * fields that are larger than one byte, as these will be in network
	 * byte order */
	printf("UDP: source=%u dest=%u len=%u checksum=%u\n",
			ntohs(udp->source), ntohs(udp->dest),
			ntohs(udp->len), ntohs(udp->check));
}


/* Due to the amount of error checking required in our main function, it
 * is a lot simpler and tidier to place all the calls to various libtrace
 * destroy functions into a separate function.
 */
static void libtrace_cleanup(libtrace_t *trace, libtrace_packet_t *packet) {
	
	/* It's very important to ensure that we aren't trying to destroy
         * a NULL structure, so each of the destroy calls will only occur
         * if the structure exists */
	if (trace)
		trace_destroy(trace);

	if (packet)
		trace_destroy_packet(packet);

}

int main(int argc, char *argv[])
{
	/* This is essentially the same main function from readdemo.c */
	
	libtrace_t *trace = NULL;
	libtrace_packet_t *packet = NULL;

	/* Ensure we have at least one argument after the program name */
        if (argc < 2) {
                fprintf(stderr, "Usage: %s inputURI\n", argv[0]);
                return 1;
        }	
	
	packet = trace_create_packet();

	if (packet == NULL) {
		perror("Creating libtrace packet");
		libtrace_cleanup(trace, packet);
		return 1;
	}

	trace = trace_create(argv[1]);

	if (trace_is_err(trace)) {
		trace_perror(trace,"Opening trace file");
		libtrace_cleanup(trace, packet);
		return 1;
	}

	if (trace_start(trace) == -1) {
		trace_perror(trace,"Starting trace");
		libtrace_cleanup(trace, packet);
		return 1;
	}


	while (trace_read_packet(trace,packet)>0) {
		per_packet(packet);
	}


	if (trace_is_err(trace)) {
		trace_perror(trace,"Reading packets");
		libtrace_cleanup(trace, packet);
		return 1;
	}

	libtrace_cleanup(trace, packet);
	return 0;
}