Commit a4f297ea authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾 Committed by GitHub

Use a pcap wrapper instead of tcpdump (#10)

parent e097fb8e
...@@ -17,7 +17,8 @@ Additionally, IGMPv2 and MLDv1 are implemented alongside with PIM-DM to detect i ...@@ -17,7 +17,8 @@ Additionally, IGMPv2 and MLDv1 are implemented alongside with PIM-DM to detect i
- Unicast routing protocol - Unicast routing protocol
- Python3 (we have written all code to be compatible with at least Python v3.3) - Python3 (we have written all code to be compatible with at least Python v3.3)
- pip (to install all dependencies) - pip (to install all dependencies)
- tcpdump - libpcap-dev
- python3-dev
# Installation # Installation
......
/* based on https://github.com/the-tcpdump-group/tcpdump */
#ifndef FILTER_H
#define FILTER_H
#define MAXIMUM_SNAPLEN 262144
#include <stdio.h>
#include <pcap.h>
int filter_try_compile(struct bpf_program *fp, const char *cmdbuf)
{
int dump_dlt, ret;
pcap_t *pd;
dump_dlt = DLT_EN10MB;
fprintf(stderr, "Warning: assuming Ethernet\n");
pd = pcap_open_dead(dump_dlt, MAXIMUM_SNAPLEN);
ret = pcap_compile(pd, fp, cmdbuf, 1, 0);
if (ret < 0)
fprintf(stderr, "%s", pcap_geterr(pd));
pcap_close(pd);
return (ret);
}
#endif /* FILTER_H */
This source diff could not be displayed because it is too large. You can view the blob instead.
#include <pcap.h>
import struct
ctypedef unsigned int u_int
ctypedef unsigned char u_char
ctypedef unsigned short int u_short
ctypedef u_int bpf_u_int32
cdef extern from "pcap.h":
struct bpf_insn:
u_short code
u_char jt
u_char jf
bpf_u_int32 k
struct bpf_program:
bpf_insn *bf_insns
u_int bf_len
cdef extern from "pcap.h":
void pcap_freecode(bpf_program *fp)
cdef extern from "filter.h":
int filter_try_compile(bpf_program *fp, const char *cmdbuf)
cdef class bpf:
"""bpf(filter) -> BPF filter object"""
cdef bpf_program fcode
def __init__(self, char *filter):
if filter_try_compile(&self.fcode, filter) < 0:
raise IOError, 'bad filter'
def compiled_filter(self):
cdef bpf_insn *bf_insns
bf_insns = self.fcode.bf_insns
size = self.fcode.bf_len
return size, b''.join(
struct.pack('HBBI', bf_insns[i].code, bf_insns[i].jt, bf_insns[i].jf, bf_insns[i].k)
for i in range(size)
)
def dump(self):
cdef bpf_insn *bf_insns
cdef bpf_insn bf_insn
bf_insns = self.fcode.bf_insns
for i in range(self.fcode.bf_len):
bf_insn = bf_insns[i]
print("{ 0x%x, %d, %d, 0x%08x }," % (bf_insn.code, bf_insn.jt, bf_insn.jf, bf_insn.k))
def __dealloc__(self):
pcap_freecode(&self.fcode)
import struct import struct
import socket import socket
import ipaddress import ipaddress
import subprocess
from ctypes import create_string_buffer, addressof from ctypes import create_string_buffer, addressof
from pcap_wrapper import bpf
SO_ATTACH_FILTER = 26 SO_ATTACH_FILTER = 26
ETH_P_IP = 0x0800 # Internet Protocol packet ETH_P_IP = 0x0800 # Internet Protocol packet
...@@ -14,25 +14,17 @@ def get_s_g_bpf_filter_code(source, group, interface_name): ...@@ -14,25 +14,17 @@ def get_s_g_bpf_filter_code(source, group, interface_name):
ip_source_version = ipaddress.ip_address(source).version ip_source_version = ipaddress.ip_address(source).version
ip_group_version = ipaddress.ip_address(group).version ip_group_version = ipaddress.ip_address(group).version
if ip_source_version == ip_group_version == 4: if ip_source_version == ip_group_version == 4:
# cmd = "tcpdump -ddd \"(udp or icmp) and host %s and dst %s\"" % (source, group) # bpf_filter_str = "(udp or icmp) and host %s and dst %s" % (source, group)
cmd = "tcpdump -ddd \"(ip proto not 2) and host %s and dst %s\"" % (source, group) bpf_filter_str = "(ip proto not 2) and host %s and dst %s" % (source, group)
protocol = ETH_P_IP protocol = ETH_P_IP
elif ip_source_version == ip_group_version == 6: elif ip_source_version == ip_group_version == 6:
# TODO: allow ICMPv6 echo request/echo response to be considered multicast packets # TODO: allow ICMPv6 echo request/echo response to be considered multicast packets
cmd = "tcpdump -ddd \"(ip6 proto not 58) and host %s and dst %s\"" % (source, group) bpf_filter_str = "(ip6 proto not 58) and host %s and dst %s" % (source, group)
protocol = ETH_P_IPV6 protocol = ETH_P_IPV6
else: else:
raise Exception("Unknown IP family") raise Exception("Unknown IP family")
result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) num, bpf_filter = bpf(bpf_filter_str.encode()).compiled_filter()
bpf_filter = b''
tmp = result.stdout.read().splitlines()
num = int(tmp[0])
for line in tmp[1:]:
print(line)
bpf_filter += struct.pack("HBBI", *tuple(map(int, line.split(b' '))))
print(num) print(num)
# defined in linux/filter.h. # defined in linux/filter.h.
......
import sys import sys
from setuptools import setup, find_packages from setuptools import setup, find_packages, Extension
# we only support Python 3 version >= 3.3 # we only support Python 3 version >= 3.3
if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 3): if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 3):
...@@ -26,6 +26,11 @@ setup( ...@@ -26,6 +26,11 @@ setup(
'igmp==1.0.2', 'igmp==1.0.2',
], ],
packages=find_packages(exclude=["docs"]), packages=find_packages(exclude=["docs"]),
ext_modules = [Extension(
name="pcap_wrapper",
sources = ["pcap.c"],
libraries=["pcap"],
)],
entry_points={ entry_points={
"console_scripts": [ "console_scripts": [
"pim-dm = pimdm.Run:main", "pim-dm = pimdm.Run:main",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment