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 #include <unistd.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 
39 #include <pcap-int.h>
40 #include <pcap.h>
41 #include <net/ethernet.h>
42 
43 #define ETHER_TYPE_TEST "0x8822"
44 #define SNAPLEN 96
45 #define MAXPROG 128
46 
47 char errbuf[PCAP_ERRBUF_SIZE];
48 
49 void usage(char* message) {
50 	if (message != NULL)
51 		printf ("error: %s\n", message);
52 	printf("usage: ether_reflect -i interface -e ethertype "
53 	       "-a address -t timeout -p -d\n");
54 	exit(1);
55 }
56 
57 int main(int argc, char **argv)
58 {
59 	int ch;
60 	int debug = 0, promisc = 0;
61 	int timeout = 100;
62 	bpf_u_int32 localnet=0, netmask=0;
63 	unsigned int error = 0;
64 	char *interface = NULL;
65 	char *proto = ETHER_TYPE_TEST;
66 	char in_string[MAXPROG];
67 	char tmp[ETHER_ADDR_LEN];
68 	char addr[ETHER_ADDR_LEN];
69 	char *user_addr = NULL;
70 	pcap_t *capture;
71 	struct bpf_program program;
72 	struct pcap_pkthdr *header;
73 	unsigned char *packet = NULL;
74 
75 	while ((ch = getopt(argc, argv, "a:e:i:t:pd")) != -1) {
76 		switch (ch) {
77 		case 'a':
78 			user_addr = optarg;
79 			break;
80 		case 'e':
81 			proto = optarg;
82 			break;
83 		case 'i':
84 			interface = optarg;
85 			break;
86 		case 'p':
87 			promisc = 1;
88 			break;
89 		case 't':
90 			timeout = atoi(optarg);
91 			break;
92 		case 'd':
93 			debug = 1;
94 			break;
95 		case '?':
96 		default:
97 			usage("invalid arguments");
98 		}
99 	}
100 	argc -= optind;
101 	argv += optind;
102 
103 	if (interface == NULL)
104 		usage("You must specify an interface");
105 
106 	if (user_addr != NULL)
107 		ether_aton_r(user_addr, (struct ether_addr *)&tmp);
108 
109 	if ((capture = pcap_open_live(interface, SNAPLEN, promisc, timeout,
110 				      &errbuf[0])) == NULL)
111 		usage(errbuf);
112 
113 	snprintf(&in_string[0], MAXPROG, "ether proto %s\n", proto);
114 
115 	if (pcap_lookupnet(interface, &localnet, &netmask, errbuf) < 0)
116 		usage(errbuf);
117 
118 	if (pcap_compile(capture, &program, in_string, 1, netmask) < 0)
119 		usage(errbuf);
120 
121 	if (pcap_setfilter(capture, &program) < 0)
122 		usage(errbuf);
123 
124 	if (pcap_setdirection(capture, PCAP_D_IN) < 0)
125 		usage(errbuf);
126 
127 	while (1) {
128 		error = pcap_next_ex(capture, &header,
129 				     (const unsigned char **)&packet);
130 		if (error == 0)
131 			continue;
132 		if (error == -1)
133 			usage("packet read error");
134 		if (error == -2)
135 			usage("savefile?  invalid!");
136 
137 		if (debug) {
138 			printf ("got packet of %d length\n", header->len);
139 			printf ("header %s\n",
140 				ether_ntoa((const struct ether_addr*)
141 					   &packet[0]));
142 			printf ("header %s\n",
143 				ether_ntoa((const struct ether_addr*)
144 					   &packet[ETHER_ADDR_LEN]));
145 		}
146 
147 		/*
148 		 * If the user did not supply an address then we simply
149 		 * reverse the source and destination addresses.
150 		 */
151 		if (user_addr == NULL) {
152 			bcopy(packet, &tmp, ETHER_ADDR_LEN);
153 			bcopy(&packet[ETHER_ADDR_LEN], packet, ETHER_ADDR_LEN);
154 			bcopy(&tmp, &packet[ETHER_ADDR_LEN], ETHER_ADDR_LEN);
155 		} else {
156 			bcopy(&tmp, packet, ETHER_ADDR_LEN);
157 		}
158 		if (pcap_inject(capture, packet, header->len) < 0)
159 			if (debug)
160 				pcap_perror(capture, "pcap_inject");
161 	}
162 }
163