#define ETHERTYPE_PPPOE 0x8864
#endif
+#ifndef ETHERTYPE_IPV6
+# include <net/if_ether.h> /* ETH_P_IPV6 for GNU/kfreebsd */
+# define ETHERTYPE_IPV6 ETH_P_IPV6
+#endif
+
#include <net/if.h> /* struct ifreq */
#include <netinet/in_systm.h> /* n_long */
#include <netinet/ip.h> /* struct ip */
+#include <netinet/ip6.h> /* struct ip6_hdr */
#define __FAVOR_BSD
#include <netinet/tcp.h> /* struct tcphdr */
#include <netinet/udp.h> /* struct udphdr */
const u_char *);
static void decode_ip(const u_char *pdata, const uint32_t len,
pktsummary *sm);
+static void decode_ipv6(const u_char *pdata, const uint32_t len,
+ pktsummary *sm);
/* Link-type header information */
static const linkhdr_t linkhdrs[] = {
}
/*
- * Returns the minimum caplen needed to decode everything up to the TCP/UDP
+ * Returns the minimum snaplen needed to decode everything up to the TCP/UDP
* packet headers. Argument lh is not allowed to be NULL.
*/
int
-getcaplen(const linkhdr_t *lh)
+getsnaplen(const linkhdr_t *lh)
{
assert(lh != NULL);
return (lh->hdrlen + IP_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
return (inet_ntoa(in));
}
+char ip6str[INET6_ADDRSTRLEN];
+
+char *
+ip6_to_str(const struct in6_addr *ip6)
+{
+ ip6str[0] = '\0';
+ inet_ntop(AF_INET6, ip6, ip6str, sizeof(ip6str));
+
+ return (ip6str);
+}
+
/* Decoding functions. */
static void
decode_ether(u_char *user _unused_,
type = ntohs( hdr->ether_type );
switch (type) {
case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
if (!want_pppoe) {
decode_ip(pdata + ETHER_HDR_LEN,
pheader->caplen - ETHER_HDR_LEN, &sm);
sm.time = pheader->ts.tv_sec;
acct_for(&sm);
}
+ else if (family == AF_INET6) {
+ /* XXX: Check this! */
+ decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
+ sm.time = pheader->ts.tv_sec;
+ acct_for(&sm);
+ }
else
verbosef("loop: unknown family (%x)", family);
}
type = ntohs( hdr->ether_type );
switch (type) {
case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
decode_ip(pdata + SLL_HDR_LEN, pheader->caplen - SLL_HDR_LEN, &sm);
sm.time = pheader->ts.tv_sec;
acct_for(&sm);
{
const struct ip *hdr = (const struct ip *)pdata;
+ if (hdr->ip_v == 6) {
+ /* Redirect parsing of IPv6 packets. */
+ decode_ipv6(pdata, len, sm);
+ return;
+ }
if (len < IP_HDR_LEN) {
verbosef("ip: packet too short (%u bytes)", len);
return;
}
sm->len = ntohs(hdr->ip_len);
+ sm->af = AF_INET;
sm->proto = hdr->ip_p;
sm->src_ip = hdr->ip_src.s_addr;
sm->dest_ip = hdr->ip_dst.s_addr;
}
}
+static void
+decode_ipv6(const u_char *pdata, const uint32_t len, pktsummary *sm)
+{
+ const struct ip6_hdr *hdr = (const struct ip6_hdr *)pdata;
+
+ if (len < IPV6_HDR_LEN) {
+ verbosef("ipv6: packet too short (%u bytes)", len);
+ return;
+ }
+
+ sm->len = ntohs(hdr->ip6_plen) + IPV6_HDR_LEN;
+ sm->af = AF_INET6;
+ sm->proto = hdr->ip6_nxt;
+ memcpy(&sm->src_ip6, &hdr->ip6_src, sizeof(sm->src_ip6));
+ memcpy(&sm->dest_ip6, &hdr->ip6_dst, sizeof(sm->dest_ip6));
+
+ switch (sm->proto) {
+ case IPPROTO_TCP: {
+ const struct tcphdr *thdr =
+ (const struct tcphdr *)(pdata + IPV6_HDR_LEN);
+ if (len < IPV6_HDR_LEN + TCP_HDR_LEN) {
+ verbosef("tcp6: packet too short (%u bytes)", len);
+ return;
+ }
+ sm->src_port = ntohs(thdr->th_sport);
+ sm->dest_port = ntohs(thdr->th_dport);
+ sm->tcp_flags = thdr->th_flags &
+ (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
+ break;
+ }
+
+ case IPPROTO_UDP: {
+ const struct udphdr *uhdr =
+ (const struct udphdr *)(pdata + IPV6_HDR_LEN);
+ if (len < IPV6_HDR_LEN + UDP_HDR_LEN) {
+ verbosef("udp6: packet too short (%u bytes)", len);
+ return;
+ }
+ sm->src_port = ntohs(uhdr->uh_sport);
+ sm->dest_port = ntohs(uhdr->uh_dport);
+ break;
+ }
+
+ case IPPROTO_ICMPV6:
+ /* known protocol, don't complain about it */
+ break;
+
+ default:
+ verbosef("ipv6: unknown protocol %d", sm->proto);
+ }
+}
+
/* vim:set ts=3 sw=3 tw=78 expandtab: */