blob: 754d6775309ffcb60ea8a1f973804b38c5b97f9c [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
174 printf("PACKET NR: %d\n", ++pktcnt);
175 iph = NULL;
176 curr_len = ETH_HLEN;
177
178 printf("INDEV=%s\nOUTDEV=%s\nPHYSINDEV=%s\nPHYSOUTDEV=%s\n"
179 "PREFIX='%s'", msg->indev, msg->outdev, msg->physindev,
180 msg->physoutdev, msg->prefix);
181
182 ptm = localtime(&msg->stamp.tv_sec);
183 strftime (time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", ptm);
184 printf("\nARRIVAL TIME: %s\nMARK=%lu\nHOOK=%s\n", time_str,
185 msg->mark, hookstr[msg->hook]);
186
187 if (msg->data_len < curr_len) {
188 printf("====>Packet smaller than Ethernet header "
189 "length<====\n");
190 goto letscontinue;
191 }
192
193 printf("::::::::ETHERNET:HEADER::::::::\n");
194
195 ehdr = (struct ethhdr *)msg->data;
196 printf("MAC SRC=%s\n", ether_ntoa((const struct ether_addr *)
197 ehdr->h_source));
198 printf("MAC DST=%s\nETHERNET PROTOCOL=", ether_ntoa(
199 (const struct ether_addr *)ehdr->h_dest));
200 etype = getethertypebynumber(ntohs(ehdr->h_proto));
201 if (!etype)
202 printf("0x%x\n", ntohs(ehdr->h_proto));
203 else
204 printf("%s\n", etype->e_name);
205
206 if (ehdr->h_proto == htons(ETH_P_8021Q)) {
207 struct vlan_hdr *vlanh = (struct vlan_hdr *)
208 (((char *)ehdr) + curr_len);
209 printf("::::::::::VLAN:HEADER::::::::::\n");
210 curr_len += VLAN_HLEN;
211 if (msg->data_len < curr_len) {
212 printf("====>Packet only contains partial "
213 "VLAN header<====\n");
214 goto letscontinue;
215 }
216
217 printf("VLAN TCI=%d\n", ntohs(vlanh->TCI));
218 printf("VLAN ENCAPS PROTOCOL=");
219 etype = getethertypebynumber(ntohs(vlanh->encap));
220 if (!etype)
221 printf("0x%x\n", ntohs(vlanh->encap));
222 else
223 printf("%s\n", etype->e_name);
224 if (ehdr->h_proto == htons(ETH_P_IP))
225 iph = (struct iphdr *)(vlanh + 1);
226 } else if (ehdr->h_proto == htons(ETH_P_IP))
227 iph = (struct iphdr *)(((char *)ehdr) + curr_len);
228 if (!iph)
229 goto letscontinue;
230
231 curr_len += sizeof(struct iphdr);
232 if (msg->data_len < curr_len || msg->data_len <
233 (curr_len += iph->ihl * 4 - sizeof(struct iphdr))) {
234 printf("====>Packet only contains partial IP "
235 "header<====\n");
236 goto letscontinue;
237 }
238
239 printf(":::::::::::IP:HEADER:::::::::::\n");
240 printf("IP SRC ADDR=");
241 for (i = 0; i < 4; i++)
242 printf("%d%s", ((unsigned char *)&iph->saddr)[i],
243 (i == 3) ? "" : ".");
244 printf("\nIP DEST ADDR=");
245 for (i = 0; i < 4; i++)
246 printf("%d%s", ((unsigned char *)&iph->daddr)[i],
247 (i == 3) ? "" : ".");
248 printf("\nIP PROTOCOL=");
249 if (!(prototype = getprotobynumber(iph->protocol)))
250 printf("%d\n", iph->protocol);
251 else
252 printf("%s\n", prototype->p_name);
253
254 if (iph->protocol != IPPROTO_ICMP)
255 goto letscontinue;
256
257 icmph = (struct icmphdr *)(((char *)ehdr) + curr_len);
258 curr_len += 4;
259 if (msg->data_len < curr_len) {
260truncated_icmp:
261 printf("====>Packet only contains partial ICMP "
262 "header<====\n");
263 goto letscontinue;
264 }
265 if (icmph->type != ICMP_ECHO && icmph->type != ICMP_ECHOREPLY)
266 goto letscontinue;
267
268 curr_len += 4;
269 if (msg->data_len < curr_len)
270 goto truncated_icmp;
271 /* Normally the process id, it's sent out in machine
272 * byte order */
273
274 printf("ICMP_ECHO IDENTIFIER=%u\n", icmph->un.echo.id);
275 printf("ICMP_ECHO SEQ NR=%u\n", ntohs(icmph->un.echo.sequence));
276
277letscontinue:
278 printf("===>Total Packet length: %d, of which we examined "
279 "%d bytes\n", msg->data_len, curr_len);
280 printf("###############################\n"
281 "######END#OF##PACKET#DUMP######\n"
282 "###############################\n");
283 }
284
285 return 0;
286}