blob: cbb6c4f29db3fbd808f96d77a95a826a7aa1728e [file] [log] [blame]
Bart De Schuymerb134dac2004-11-20 12:54:02 +00001
2/*
3 * Simple example program to log packets received with the ulog
4 * watcher of ebtables.
5 *
6 * usage:
7 * Add the appropriate ebtables ulog rule, e.g. (0 < NLGROUP < 33):
8 * ebtables -A FORWARD --ulog-nlgroup NLGROUP
9 * Start this application somewhere:
10 * test_ulog NLGROUP
11 *
12 * compile with make test_ulog KERNEL_INCLUDES=<path_to_kernel_include_dir>
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29
30#include <asm/types.h>
31#include <sys/socket.h>
32#include <sys/time.h>
33#include <linux/netlink.h>
34#include <stdlib.h>
35#include <stdio.h>
36#include <unistd.h>
37#include <netdb.h>
38#include <errno.h>
39#include <netinet/if_ether.h>
40#include <netinet/ether.h>
41#include <netinet/ip.h>
42#include <netinet/ip_icmp.h>
43#include "../../include/ebtables_u.h"
44#include "../../include/ethernetdb.h"
45#include <linux/netfilter_bridge/ebt_ulog.h>
46
47/* <linux/if_vlan.h> doesn't hand this to userspace :-( */
48#define VLAN_HLEN 4
49struct vlan_hdr {
50 unsigned short TCI;
51 unsigned short encap;
52};
53
54static struct sockaddr_nl sa_local =
55{
56 .nl_family = AF_NETLINK,
57 .nl_groups = 1,
58};
59
60static struct sockaddr_nl sa_kernel =
61{
62 .nl_family = AF_NETLINK,
63 .nl_pid = 0,
64 .nl_groups = 1,
65};
66
67static const char *hookstr[NF_BR_NUMHOOKS] =
68{
69 [NF_BR_POST_ROUTING] "POSTROUTING",
70 [NF_BR_PRE_ROUTING] "PREROUTING",
71 [NF_BR_LOCAL_OUT] "OUTPUT",
72 [NF_BR_LOCAL_IN] "INPUT",
73 [NF_BR_BROUTING] "BROUTING",
74 [NF_BR_FORWARD] "FORWARD"
75};
76
77#define DEBUG_QUEUE 0
78#define BUFLEN 65536
79static char buf[BUFLEN];
80static int sfd;
81
82/* Get the next ebt_ulog packet, talk to the kernel if necessary */
83ebt_ulog_packet_msg_t *ulog_get_packet()
84{
85 static struct nlmsghdr *nlh = NULL;
86 static int len, remain_len;
87 static int pkts_per_msg = 0;
88 ebt_ulog_packet_msg_t *msg;
89 socklen_t addrlen = sizeof(sa_kernel);
90
91 if (!nlh) {
92recv_new:
93 if (pkts_per_msg && DEBUG_QUEUE)
94 printf("PACKETS IN LAST MSG: %d\n", pkts_per_msg);
95 pkts_per_msg = 0;
96 len = recvfrom(sfd, buf, BUFLEN, 0,
97 (struct sockaddr *)&sa_kernel, &addrlen);
98 if (errno == EINTR)
99 goto recv_new;
100 if (addrlen != sizeof(sa_kernel)) {
101 printf("addrlen %d != %d\n", addrlen,
102 sizeof(sa_kernel));
103 exit(-1);
104 }
105 if (len == -1) {
106 perror("recvmsg");
107 exit(-1);
108 }
109 nlh = (struct nlmsghdr *)buf;
110 if (nlh->nlmsg_flags & MSG_TRUNC || len > BUFLEN) {
111 printf("Packet truncated");
112 exit(-1);
113 }
114 if (!NLMSG_OK(nlh, BUFLEN)) {
115 perror("Netlink message parse error\n");
116 return NULL;
117 }
118 }
119
120 msg = NLMSG_DATA(nlh);
121
122 remain_len = (len - ((char *)nlh - buf));
123 if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_type != NLMSG_DONE)
124 nlh = NLMSG_NEXT(nlh, remain_len);
125 else
126 nlh = NULL;
127
128 pkts_per_msg++;
129 return msg;
130}
131
132int main(int argc, char **argv)
133{
134 int i, curr_len, pktcnt = 0;
135 int rcvbufsize = BUFLEN;
136 ebt_ulog_packet_msg_t *msg;
137 struct ethhdr *ehdr;
138 struct ethertypeent *etype;
139 struct protoent *prototype;
140 struct iphdr *iph;
141 struct icmphdr *icmph;
142 struct tm* ptm;
143 char time_str[40], *ctmp;
144
145 if (argc == 2) {
146 i = strtoul(argv[1], &ctmp, 10);
147 if (*ctmp != '\0' || i < 1 || i > 32) {
148 printf("Usage: %s <group number>\nWith 0 < group "
149 "number < 33\n", argv[0]);
150 exit(0);
151 }
152 sa_local.nl_groups = sa_kernel.nl_groups = 1 << (i - 1);
153 }
154
155 sa_local.nl_pid = getpid();
156 sfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
157 if (!sfd) {
158 perror("socket");
159 exit(-1);
160 }
161
162 if (bind(sfd, (struct sockaddr *)(&sa_local), sizeof(sa_local)) ==
163 -1) {
164 perror("bind");
165 exit(-1);
166 }
167 i = setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
168 sizeof(rcvbufsize));
169
170 while (1) {
171 if (!(msg = ulog_get_packet()))
172 continue;
173
Bart De Schuymer51ad7782004-11-21 17:00:37 +0000174 if (msg->version != EBT_ULOG_VERSION) {
175 printf("WRONG VERSION: %d INSTEAD OF %d\n",
176 msg->version, EBT_ULOG_VERSION);
177 continue;
178 }
Bart De Schuymerb134dac2004-11-20 12:54:02 +0000179 printf("PACKET NR: %d\n", ++pktcnt);
180 iph = NULL;
181 curr_len = ETH_HLEN;
182
183 printf("INDEV=%s\nOUTDEV=%s\nPHYSINDEV=%s\nPHYSOUTDEV=%s\n"
184 "PREFIX='%s'", msg->indev, msg->outdev, msg->physindev,
185 msg->physoutdev, msg->prefix);
186
187 ptm = localtime(&msg->stamp.tv_sec);
188 strftime (time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", ptm);
189 printf("\nARRIVAL TIME: %s\nMARK=%lu\nHOOK=%s\n", time_str,
190 msg->mark, hookstr[msg->hook]);
191
192 if (msg->data_len < curr_len) {
193 printf("====>Packet smaller than Ethernet header "
194 "length<====\n");
195 goto letscontinue;
196 }
197
198 printf("::::::::ETHERNET:HEADER::::::::\n");
199
200 ehdr = (struct ethhdr *)msg->data;
201 printf("MAC SRC=%s\n", ether_ntoa((const struct ether_addr *)
202 ehdr->h_source));
203 printf("MAC DST=%s\nETHERNET PROTOCOL=", ether_ntoa(
204 (const struct ether_addr *)ehdr->h_dest));
205 etype = getethertypebynumber(ntohs(ehdr->h_proto));
206 if (!etype)
207 printf("0x%x\n", ntohs(ehdr->h_proto));
208 else
209 printf("%s\n", etype->e_name);
210
211 if (ehdr->h_proto == htons(ETH_P_8021Q)) {
212 struct vlan_hdr *vlanh = (struct vlan_hdr *)
213 (((char *)ehdr) + curr_len);
214 printf("::::::::::VLAN:HEADER::::::::::\n");
215 curr_len += VLAN_HLEN;
216 if (msg->data_len < curr_len) {
217 printf("====>Packet only contains partial "
218 "VLAN header<====\n");
219 goto letscontinue;
220 }
221
222 printf("VLAN TCI=%d\n", ntohs(vlanh->TCI));
223 printf("VLAN ENCAPS PROTOCOL=");
224 etype = getethertypebynumber(ntohs(vlanh->encap));
225 if (!etype)
226 printf("0x%x\n", ntohs(vlanh->encap));
227 else
228 printf("%s\n", etype->e_name);
229 if (ehdr->h_proto == htons(ETH_P_IP))
230 iph = (struct iphdr *)(vlanh + 1);
231 } else if (ehdr->h_proto == htons(ETH_P_IP))
232 iph = (struct iphdr *)(((char *)ehdr) + curr_len);
233 if (!iph)
234 goto letscontinue;
235
236 curr_len += sizeof(struct iphdr);
237 if (msg->data_len < curr_len || msg->data_len <
238 (curr_len += iph->ihl * 4 - sizeof(struct iphdr))) {
239 printf("====>Packet only contains partial IP "
240 "header<====\n");
241 goto letscontinue;
242 }
243
244 printf(":::::::::::IP:HEADER:::::::::::\n");
245 printf("IP SRC ADDR=");
246 for (i = 0; i < 4; i++)
247 printf("%d%s", ((unsigned char *)&iph->saddr)[i],
248 (i == 3) ? "" : ".");
249 printf("\nIP DEST ADDR=");
250 for (i = 0; i < 4; i++)
251 printf("%d%s", ((unsigned char *)&iph->daddr)[i],
252 (i == 3) ? "" : ".");
253 printf("\nIP PROTOCOL=");
254 if (!(prototype = getprotobynumber(iph->protocol)))
255 printf("%d\n", iph->protocol);
256 else
257 printf("%s\n", prototype->p_name);
258
259 if (iph->protocol != IPPROTO_ICMP)
260 goto letscontinue;
261
262 icmph = (struct icmphdr *)(((char *)ehdr) + curr_len);
263 curr_len += 4;
264 if (msg->data_len < curr_len) {
265truncated_icmp:
266 printf("====>Packet only contains partial ICMP "
267 "header<====\n");
268 goto letscontinue;
269 }
270 if (icmph->type != ICMP_ECHO && icmph->type != ICMP_ECHOREPLY)
271 goto letscontinue;
272
273 curr_len += 4;
274 if (msg->data_len < curr_len)
275 goto truncated_icmp;
276 /* Normally the process id, it's sent out in machine
277 * byte order */
278
279 printf("ICMP_ECHO IDENTIFIER=%u\n", icmph->un.echo.id);
280 printf("ICMP_ECHO SEQ NR=%u\n", ntohs(icmph->un.echo.sequence));
281
282letscontinue:
283 printf("===>Total Packet length: %d, of which we examined "
284 "%d bytes\n", msg->data_len, curr_len);
285 printf("###############################\n"
286 "######END#OF##PACKET#DUMP######\n"
287 "###############################\n");
288 }
289
290 return 0;
291}