3 * Simple example program to log packets received with the ulog
7 * Add the appropriate ebtables ulog rule, e.g. (0 < NLGROUP < 33):
8 * ebtables -A FORWARD --ulog-nlgroup NLGROUP
9 * Start this application somewhere:
12 * compile with make test_ulog KERNEL_INCLUDES=<path_to_kernel_include_dir>
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.
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.
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.
30 #include <asm/types.h>
31 #include <sys/socket.h>
34 #include <linux/netlink.h>
40 #include <netinet/if_ether.h>
41 #include <netinet/ether.h>
42 #include <netinet/ip.h>
43 #include <netinet/ip_icmp.h>
44 #include "../../include/ebtables_u.h"
45 #include "../../include/ethernetdb.h"
46 #include <linux/netfilter_bridge/ebt_ulog.h>
48 /* <linux/if_vlan.h> doesn't hand this to userspace :-( */
55 static struct sockaddr_nl sa_local
=
57 .nl_family
= AF_NETLINK
,
61 static struct sockaddr_nl sa_kernel
=
63 .nl_family
= AF_NETLINK
,
68 static const char *hookstr
[NF_BR_NUMHOOKS
] =
70 [NF_BR_POST_ROUTING
] "POSTROUTING",
71 [NF_BR_PRE_ROUTING
] "PREROUTING",
72 [NF_BR_LOCAL_OUT
] "OUTPUT",
73 [NF_BR_LOCAL_IN
] "INPUT",
74 [NF_BR_BROUTING
] "BROUTING",
75 [NF_BR_FORWARD
] "FORWARD"
80 static char buf
[BUFLEN
];
83 /* Get the next ebt_ulog packet, talk to the kernel if necessary */
84 ebt_ulog_packet_msg_t
*ulog_get_packet()
86 static struct nlmsghdr
*nlh
= NULL
;
87 static int len
, remain_len
;
88 static int pkts_per_msg
= 0;
89 ebt_ulog_packet_msg_t
*msg
;
90 socklen_t addrlen
= sizeof(sa_kernel
);
94 if (pkts_per_msg
&& DEBUG_QUEUE
)
95 printf("PACKETS IN LAST MSG: %d\n", pkts_per_msg
);
97 len
= recvfrom(sfd
, buf
, BUFLEN
, 0,
98 (struct sockaddr
*)&sa_kernel
, &addrlen
);
99 if (addrlen
!= sizeof(sa_kernel
)) {
100 printf("addrlen %u != %u\n", addrlen
,
101 (uint32_t)sizeof(sa_kernel
));
110 nlh
= (struct nlmsghdr
*)buf
;
111 if (nlh
->nlmsg_flags
& MSG_TRUNC
|| len
> BUFLEN
) {
112 printf("Packet truncated");
115 if (!NLMSG_OK(nlh
, BUFLEN
)) {
116 perror("Netlink message parse error\n");
121 msg
= NLMSG_DATA(nlh
);
123 remain_len
= (len
- ((char *)nlh
- buf
));
124 if (nlh
->nlmsg_flags
& NLM_F_MULTI
&& nlh
->nlmsg_type
!= NLMSG_DONE
)
125 nlh
= NLMSG_NEXT(nlh
, remain_len
);
133 int main(int argc
, char **argv
)
135 int i
, curr_len
, pktcnt
= 0;
136 int rcvbufsize
= BUFLEN
;
137 ebt_ulog_packet_msg_t
*msg
;
139 struct ethertypeent
*etype
;
140 struct protoent
*prototype
;
142 struct icmphdr
*icmph
;
144 char time_str
[40], *ctmp
;
147 i
= strtoul(argv
[1], &ctmp
, 10);
148 if (*ctmp
!= '\0' || i
< 1 || i
> 32) {
149 printf("Usage: %s <group number>\nWith 0 < group "
150 "number < 33\n", argv
[0]);
153 sa_local
.nl_groups
= sa_kernel
.nl_groups
= 1 << (i
- 1);
156 sa_local
.nl_pid
= getpid();
157 sfd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_NFLOG
);
163 if (bind(sfd
, (struct sockaddr
*)(&sa_local
), sizeof(sa_local
)) ==
168 i
= setsockopt(sfd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbufsize
,
172 if (!(msg
= ulog_get_packet()))
175 if (msg
->version
!= EBT_ULOG_VERSION
) {
176 printf("WRONG VERSION: %d INSTEAD OF %d\n",
177 msg
->version
, EBT_ULOG_VERSION
);
180 printf("PACKET NR: %d\n", ++pktcnt
);
184 printf("INDEV=%s\nOUTDEV=%s\nPHYSINDEV=%s\nPHYSOUTDEV=%s\n"
185 "PREFIX='%s'", msg
->indev
, msg
->outdev
, msg
->physindev
,
186 msg
->physoutdev
, msg
->prefix
);
188 ptm
= localtime(&msg
->stamp
.tv_sec
);
189 strftime (time_str
, sizeof(time_str
), "%Y-%m-%d %H:%M:%S", ptm
);
190 printf("\nARRIVAL TIME: %s\nMARK=%lu\nHOOK=%s\n", time_str
,
191 msg
->mark
, hookstr
[msg
->hook
]);
193 if (msg
->data_len
< curr_len
) {
194 printf("====>Packet smaller than Ethernet header "
199 printf("::::::::ETHERNET:HEADER::::::::\n");
201 ehdr
= (struct ethhdr
*)msg
->data
;
202 printf("MAC SRC=%s\n", ether_ntoa((const struct ether_addr
*)
204 printf("MAC DST=%s\nETHERNET PROTOCOL=", ether_ntoa(
205 (const struct ether_addr
*)ehdr
->h_dest
));
206 etype
= getethertypebynumber(ntohs(ehdr
->h_proto
));
208 printf("0x%x\n", ntohs(ehdr
->h_proto
));
210 printf("%s\n", etype
->e_name
);
212 if (ehdr
->h_proto
== htons(ETH_P_8021Q
)) {
213 struct vlan_hdr
*vlanh
= (struct vlan_hdr
*)
214 (((char *)ehdr
) + curr_len
);
215 printf("::::::::::VLAN:HEADER::::::::::\n");
216 curr_len
+= VLAN_HLEN
;
217 if (msg
->data_len
< curr_len
) {
218 printf("====>Packet only contains partial "
219 "VLAN header<====\n");
223 printf("VLAN TCI=%d\n", ntohs(vlanh
->TCI
));
224 printf("VLAN ENCAPS PROTOCOL=");
225 etype
= getethertypebynumber(ntohs(vlanh
->encap
));
227 printf("0x%x\n", ntohs(vlanh
->encap
));
229 printf("%s\n", etype
->e_name
);
230 if (ehdr
->h_proto
== htons(ETH_P_IP
))
231 iph
= (struct iphdr
*)(vlanh
+ 1);
232 } else if (ehdr
->h_proto
== htons(ETH_P_IP
))
233 iph
= (struct iphdr
*)(((char *)ehdr
) + curr_len
);
237 curr_len
+= sizeof(struct iphdr
);
238 if (msg
->data_len
< curr_len
|| msg
->data_len
<
239 (curr_len
+= iph
->ihl
* 4 - sizeof(struct iphdr
))) {
240 printf("====>Packet only contains partial IP "
245 printf(":::::::::::IP:HEADER:::::::::::\n");
246 printf("IP SRC ADDR=");
247 for (i
= 0; i
< 4; i
++)
248 printf("%d%s", ((unsigned char *)&iph
->saddr
)[i
],
249 (i
== 3) ? "" : ".");
250 printf("\nIP DEST ADDR=");
251 for (i
= 0; i
< 4; i
++)
252 printf("%d%s", ((unsigned char *)&iph
->daddr
)[i
],
253 (i
== 3) ? "" : ".");
254 printf("\nIP PROTOCOL=");
255 if (!(prototype
= getprotobynumber(iph
->protocol
)))
256 printf("%d\n", iph
->protocol
);
258 printf("%s\n", prototype
->p_name
);
260 if (iph
->protocol
!= IPPROTO_ICMP
)
263 icmph
= (struct icmphdr
*)(((char *)ehdr
) + curr_len
);
265 if (msg
->data_len
< curr_len
) {
267 printf("====>Packet only contains partial ICMP "
271 if (icmph
->type
!= ICMP_ECHO
&& icmph
->type
!= ICMP_ECHOREPLY
)
275 if (msg
->data_len
< curr_len
)
277 /* Normally the process id, it's sent out in machine
280 printf("ICMP_ECHO IDENTIFIER=%u\n", icmph
->un
.echo
.id
);
281 printf("ICMP_ECHO SEQ NR=%u\n", ntohs(icmph
->un
.echo
.sequence
));
284 printf("===>Total Packet length: %ld, of which we examined "
285 "%d bytes\n", msg
->data_len
, curr_len
);
286 printf("###############################\n"
287 "######END#OF##PACKET#DUMP######\n"
288 "###############################\n");