1/*
2 * Copyright (c) 2008, Neville-Neil Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * Author: George V. Neville-Neil
27 *
28 * Purpose: This program uses libpcap to read packets from the network
29 * of a specific ethertype (default is 0x8822) and reflects them back
30 * out the same interface with their destination and source mac
31 * addresses reversed.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37#include <unistd.h>
38#include <stdlib.h>
39#include <strings.h>
40
41#include <pcap-int.h>
42#include <pcap.h>
43#include <net/ethernet.h>
44
45#define ETHER_TYPE_TEST "0x8822"
46#define SNAPLEN 96
47#define MAXPROG 128
48
49char errbuf[PCAP_ERRBUF_SIZE];
50
51void usage(char* message) {
52	if (message != NULL)
53		printf ("error: %s\n", message);
54	printf("usage: ether_reflect -i interface -e ethertype "
55	       "-a address -t timeout -p -d\n");
56	exit(1);
57}
58
59int main(int argc, char **argv)
60{
61	int ch;
62	int debug = 0, promisc = 0;
63	int timeout = 100;
64	bpf_u_int32 localnet=0, netmask=0;
65	unsigned int error = 0;
66	char *interface = NULL;
67	char *proto = ETHER_TYPE_TEST;
68	char in_string[MAXPROG];
69	char tmp[ETHER_ADDR_LEN];
70	char addr[ETHER_ADDR_LEN];
71	char *user_addr = NULL;
72	pcap_t *capture;
73	struct bpf_program program;
74	struct pcap_pkthdr *header;
75	unsigned char *packet = NULL;
76
77	while ((ch = getopt(argc, argv, "a:e:i:t:pd")) != -1) {
78		switch (ch) {
79		case 'a':
80			user_addr = optarg;
81			break;
82		case 'e':
83			proto = optarg;
84			break;
85		case 'i':
86			interface = optarg;
87			break;
88		case 'p':
89			promisc = 1;
90			break;
91		case 't':
92			timeout = atoi(optarg);
93			break;
94		case 'd':
95			debug = 1;
96			break;
97		case '?':
98		default:
99			usage("invalid arguments");
100		}
101	}
102	argc -= optind;
103	argv += optind;
104
105	if (interface == NULL)
106		usage("You must specify an interface");
107
108	if (user_addr != NULL)
109		ether_aton_r(user_addr, (struct ether_addr *)&tmp);
110
111	if ((capture = pcap_open_live(interface, SNAPLEN, promisc, timeout,
112				      &errbuf[0])) == NULL)
113		usage(errbuf);
114
115	snprintf(&in_string[0], MAXPROG, "ether proto %s\n", proto);
116
117	if (pcap_lookupnet(interface, &localnet, &netmask, errbuf) < 0)
118		usage(errbuf);
119
120	if (pcap_compile(capture, &program, in_string, 1, netmask) < 0)
121		usage(errbuf);
122
123	if (pcap_setfilter(capture, &program) < 0)
124		usage(errbuf);
125
126	if (pcap_setdirection(capture, PCAP_D_IN) < 0)
127		usage(errbuf);
128
129	while (1) {
130		error = pcap_next_ex(capture, &header,
131				     (const unsigned char **)&packet);
132		if (error == 0)
133			continue;
134		if (error == -1)
135			usage("packet read error");
136		if (error == -2)
137			usage("savefile?  invalid!");
138
139		if (debug) {
140			printf ("got packet of %d length\n", header->len);
141			printf ("header %s\n",
142				ether_ntoa((const struct ether_addr*)
143					   &packet[0]));
144			printf ("header %s\n",
145				ether_ntoa((const struct ether_addr*)
146					   &packet[ETHER_ADDR_LEN]));
147		}
148
149		/*
150		 * If the user did not supply an address then we simply
151		 * reverse the source and destination addresses.
152		 */
153		if (user_addr == NULL) {
154			bcopy(packet, &tmp, ETHER_ADDR_LEN);
155			bcopy(&packet[ETHER_ADDR_LEN], packet, ETHER_ADDR_LEN);
156			bcopy(&tmp, &packet[ETHER_ADDR_LEN], ETHER_ADDR_LEN);
157		} else {
158			bcopy(&tmp, packet, ETHER_ADDR_LEN);
159		}
160		if (pcap_inject(capture, packet, header->len) < 0)
161			if (debug)
162				pcap_perror(capture, "pcap_inject");
163	}
164}
165