From 86a43d850c60d48108836734a7ba7493dd95212c Mon Sep 17 00:00:00 2001
From: gpotter2 <gabriel@potter.fr>
Date: Mon, 18 Sep 2017 21:38:08 +0200
Subject: [PATCH] Unify BPF pointers generation

---
 scapy/arch/bpf/core.py | 36 ++++--------------------------------
 scapy/arch/common.py   | 36 ++++++++++++++++++++++++++++++++++++
 scapy/arch/linux.py    | 19 +++++--------------
 3 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/scapy/arch/bpf/core.py b/scapy/arch/bpf/core.py
index 19225454..8d749dd8 100644
--- a/scapy/arch/bpf/core.py
+++ b/scapy/arch/bpf/core.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import
 from scapy.config import conf
 from scapy.error import Scapy_Exception, warning
 from scapy.data import ARPHDR_LOOPBACK, ARPHDR_ETHER
-from scapy.arch.common import get_if
+from scapy.arch.common import get_if, get_bpf_pointer
 from scapy.consts import LOOPBACK_NAME
 
 from scapy.arch.bpf.consts import *
@@ -19,7 +19,7 @@ import fcntl
 import struct
 
 from ctypes import cdll, cast, pointer, POINTER, Structure
-from ctypes import c_uint, c_uint32, c_int, c_ulong, c_char_p, c_ushort, c_ubyte
+from ctypes import c_int, c_ulong, c_char_p
 from ctypes.util import find_library
 from scapy.modules.six.moves import range
 
@@ -31,20 +31,6 @@ LIBC.ioctl.argtypes = [c_int, c_ulong, c_char_p]
 LIBC.ioctl.restype = c_int
 
 
-class bpf_insn(Structure):
-    """"The BPF instruction data structure"""
-    _fields_ = [("code", c_ushort),
-                ("jt", c_ubyte),
-                ("jf", c_ubyte),
-                ("k", c_uint32)]
-
-
-class bpf_program(Structure):
-    """"Structure for BIOCSETF"""
-    _fields_ = [("bf_len", c_uint),
-                ("bf_insns", POINTER(bpf_insn))]
-
-
 # Addresses manipulation functions
 
 def get_if_raw_addr(ifname):
@@ -127,22 +113,8 @@ def attach_filter(fd, iface, bpf_filter_string):
     if lines == []:
         raise Scapy_Exception("Got an empty BPF filter from tcpdump !")
 
-    # Allocate BPF instructions
-    size = int(lines[0])
-    bpf_insn_a = bpf_insn * size
-    bip = bpf_insn_a()
-
-    # Fill the BPF instruction structures with the byte code
-    lines = lines[1:]
-    for i in range(len(lines)):
-        values = [int(v) for v in lines[i].split()]
-        bip[i].code = c_ushort(values[0])
-        bip[i].jt = c_ubyte(values[1])
-        bip[i].jf = c_ubyte(values[2])
-        bip[i].k = c_uint(values[3])
-
-    # Create the BPF program and assign it to the interface
-    bp = bpf_program(size, bip)
+    bp = get_bpf_pointer(lines)
+    # Assign the BPF program to the interface
     ret = LIBC.ioctl(c_int(fd), BIOCSETF, cast(pointer(bp), c_char_p))
     if ret < 0:
         raise Scapy_Exception("Can't attach the BPF filter !")
diff --git a/scapy/arch/common.py b/scapy/arch/common.py
index 6b309c7a..c0113701 100644
--- a/scapy/arch/common.py
+++ b/scapy/arch/common.py
@@ -10,6 +10,8 @@ Functions common to different architectures
 import socket
 from fcntl import ioctl
 import struct
+from ctypes import POINTER, Structure
+from ctypes import c_uint, c_uint32, c_ushort, c_ubyte
 
 def get_if(iff, cmd):
     """Ease SIOCGIF* ioctl calls"""
@@ -18,3 +20,37 @@ def get_if(iff, cmd):
     ifreq = ioctl(sck, cmd, struct.pack("16s16x", iff.encode("utf8")))
     sck.close()
     return ifreq
+
+class bpf_insn(Structure):
+    """"The BPF instruction data structure"""
+    _fields_ = [("code", c_ushort),
+                ("jt", c_ubyte),
+                ("jf", c_ubyte),
+                ("k", c_uint32)]
+
+
+class bpf_program(Structure):
+    """"Structure for BIOCSETF"""
+    _fields_ = [("bf_len", c_uint),
+                ("bf_insns", POINTER(bpf_insn))]
+
+def get_bpf_pointer(tcpdump_lines):
+    """Create a BPF Pointer for TCPDump filter"""
+    # Allocate BPF instructions
+    size = int(tcpdump_lines[0])
+    bpf_insn_a = bpf_insn * size
+    bip = bpf_insn_a()
+
+    # Fill the BPF instruction structures with the byte code
+    tcpdump_lines = tcpdump_lines[1:]
+    i = 0
+    for line in tcpdump_lines:
+        values = [int(v) for v in line.split()]
+        bip[i].code = c_ushort(values[0])
+        bip[i].jt = c_ubyte(values[1])
+        bip[i].jf = c_ubyte(values[2])
+        bip[i].k = c_uint(values[3])
+        i += 1
+
+    # Create the BPF program
+    return bpf_program(size, bip)
diff --git a/scapy/arch/linux.py b/scapy/arch/linux.py
index 9a3820a0..b44b3f02 100644
--- a/scapy/arch/linux.py
+++ b/scapy/arch/linux.py
@@ -8,7 +8,7 @@ Linux specific functions.
 """
 
 from __future__ import absolute_import
-import sys,os,struct,socket,time
+import sys, os, struct, socket, time
 from select import select
 from fcntl import ioctl
 import array, ctypes
@@ -23,7 +23,7 @@ from scapy.data import *
 from scapy.supersocket import SuperSocket
 import scapy.arch
 from scapy.error import warning, Scapy_Exception, log_interactive, log_loading
-from scapy.arch.common import get_if
+from scapy.arch.common import get_if, get_bpf_pointer
 from scapy.modules.six.moves import range
 
 
@@ -152,18 +152,9 @@ def attach_filter(s, bpf_filter, iface):
             "Failed to attach filter: tcpdump returned %d", ret
         )
         return
-    nb = int(lines[0])
-    bpf = b""
-    for l in lines[1:]:
-        bpf += struct.pack("HBBI", *(int(e) for e in l.split()))
-
-    # XXX. Argl! We need to give the kernel a pointer on the BPF
-    bpf_buf = ctypes.create_string_buffer(bpf)
-    class BpfPointer(ctypes.Structure):
-        _fields_ = [ ("bf_len", ctypes.c_int),
-                     ("bf_insn", ctypes.POINTER(type(bpf_buf))) ]
-    bpfh = BpfPointer(nb, ctypes.pointer(bpf_buf))
-    s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)
+    
+    bp = get_bpf_pointer(lines)
+    s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bp)
 
 def set_promisc(s,iff,val=1):
     mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, b"")
-- 
GitLab