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 
49 char errbuf[PCAP_ERRBUF_SIZE];
50 
51 void 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 
59 int 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