Skip to content

Commit 79cf058

Browse files
gtjosephgithub-actions[bot]
authored andcommitted
Replace yappcap with scapy for packet capture.
Yappcap will never build again because of ancient Cython so it's been replaced with "scapy" which is popular and well maintained. * The extra.txt requirements file was removed as it's no longer needed. * The verify_pidf and verify_xpidf tests needed minor tweaks to make them reliable because the tests ended with the sipp scenarios before the validation could complete. * The callee_local_direct_media and caller_local_direct_media tests indicated that they needed yappcap and pyxb but they actually need neither so those dependencies were removed. The tests still have issues however so they remain skipped. * The codec_opus tests all fail for other reasons but they never get run anyway. Issue opened.
1 parent 21e4116 commit 79cf058

File tree

14 files changed

+52
-76
lines changed

14 files changed

+52
-76
lines changed

extras.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/python/asterisk/pcap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from construct.core import *
2727
from asterisk.pcap_proxy import *
2828
try:
29-
from yappcap import PcapOffline
29+
from scapy import interfaces, sendrecv, packet
3030
PCAP_AVAILABLE = True
3131
except:
3232
PCAP_AVAILABLE = False

lib/python/asterisk/pcap_proxy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, packet_type, raw_packet):
5858
self.ip_layer = None
5959
self.transport_layer = None
6060
else:
61-
self.eth_layer = ip_stack.parse(bytes(raw_packet.data))
61+
self.eth_layer = ip_stack.parse(bytes(raw_packet))
6262
self.ip_layer = self.eth_layer.next
6363
self.transport_layer = self.ip_layer.next
6464

@@ -505,7 +505,7 @@ def interpret_packet(self, packet):
505505
"""
506506
ret_packet = None
507507
if not isinstance(packet, str):
508-
hex_string = packet.data[42:]
508+
hex_string = packet[42:]
509509
ascii_string = hex_string.decode('ascii')
510510
else:
511511
ascii_string = packet

lib/python/pcap_listener.py

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,15 @@
11
from twisted.internet import abstract, protocol
2-
from yappcap import PcapLive, findalldevs, PcapTimeout
2+
import logging
3+
import scapy
4+
from scapy.all import *
5+
from scapy.config import conf
6+
import socket
7+
import os
38

9+
LOGGER = logging.getLogger(__name__)
410

5-
class PcapFile(abstract.FileDescriptor):
6-
"""Treat a live pcap capture as a file for Twisted to call select() on"""
7-
def __init__(self, protocol, interface, xfilter=None, dumpfile=None,
8-
snaplen=65535, buffer_size=0):
9-
abstract.FileDescriptor.__init__(self)
10-
11-
p = PcapLive(interface, autosave=dumpfile, snaplen=snaplen,
12-
buffer_size=buffer_size)
13-
p.immediate = True
14-
p.activate()
15-
p.blocking = False
16-
17-
if xfilter is not None:
18-
p.filter = xfilter
19-
20-
self.pcap = p
21-
self.fd = p.selectable_fd
22-
self.protocol = protocol
23-
self.protocol.makeConnection(self)
24-
self.startReading()
25-
26-
def fileno(self):
27-
return self.fd
28-
29-
def doRead(self):
30-
try:
31-
pkt = next(self.pcap)
32-
except PcapTimeout:
33-
return 0
34-
35-
# we may not have a packet if something weird happens
36-
if not pkt:
37-
# according to the twisted docs 0 implies no write done
38-
return 0
39-
40-
self.protocol.dataReceived(pkt)
41-
42-
def connectionLost(self, reason):
43-
self.protocol.connectionLost(reason)
44-
45-
46-
class PcapListener(protocol.Protocol):
47-
"""A Twisted protocol wrapper for a pcap capture"""
11+
class PcapListener():
12+
"""A A wrapper for a scapy pcap capture"""
4813
def __init__(self, interface, bpf_filter=None, dumpfile=None,
4914
callback=None, snaplen=None, buffer_size=None):
5015
"""Initialize a new PcapListener
@@ -58,19 +23,41 @@ def __init__(self, interface, bpf_filter=None, dumpfile=None,
5823
buffer_size - The ring buffer size. If None, then 0.
5924
6025
"""
26+
6127
if interface is None:
62-
interface = [x.name for x in findalldevs() if x.loopback][0]
28+
interface = self.find_first_loopback_device()
6329
if buffer_size is None:
64-
buffer_size = 0
30+
buffer_size = 8192
6531
if snaplen is None:
6632
snaplen = 65535
67-
self.pf = PcapFile(self, interface, bpf_filter, dumpfile, snaplen,
68-
buffer_size)
33+
self.pcap_writer = None
34+
35+
scapy.config.conf.use_pcap = True
6936
self.callback = callback
7037

71-
def makeConnection(self, transport):
72-
self.connectionMade()
38+
LOGGER.info("Starting capture. if: %s dumpfile: %s snap: %d bs: %d",
39+
interface, dumpfile, snaplen, buffer_size)
40+
41+
if dumpfile is not None:
42+
self.pcap_writer = PcapWriter(dumpfile, sync=True,
43+
nano=True, snaplen=snaplen, bufsz=buffer_size)
44+
45+
self.pf = AsyncSniffer(iface=interface,filter=bpf_filter,
46+
prn=self._callback)
47+
48+
self.pf.start()
7349

74-
def dataReceived(self, data):
50+
def _callback(self, packet: scapy.packet.Packet):
7551
if self.callback:
76-
self.callback(data)
52+
self.callback(packet.original)
53+
54+
if self.pcap_writer:
55+
self.pcap_writer.write(packet)
56+
return None
57+
58+
def find_first_loopback_device(self):
59+
iflist = scapy.interfaces.get_working_ifaces()
60+
for i in iflist:
61+
if "LOOPBACK" in i.flags and "UP" in i.flags:
62+
return i.name
63+
return None

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ cffi==1.17.1
66
charset-normalizer==2.0.12
77
constantly==15.1.0
88
construct==2.10.68
9-
Cython>=0.29.34,<3.0.0
109
hyperlink==21.0.0
1110
idna==3.3
1211
incremental==24.7.2
@@ -27,3 +26,4 @@ typing_extensions==4.12.2
2726
urllib3==1.26.9
2827
zope.interface==7.0.1
2928
starpy @ git+https://github.com/asterisk/[email protected]
29+
scapy==2.6.1

setupVenv.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,8 @@ function do_pip_setup {
1616
python3 -m pip install --upgrade pip
1717
python3 -m pip install wheel setuptools build
1818
python3 -m pip install -r ./requirements.txt
19-
python3 -m pip install -r ./extras.txt || {
20-
echo "**************************" >&2
21-
echo "Some optional python requirements failed to install. The following tests may not run:" >&2
22-
grep -lEr "python\s*:\s*[']?yappcap" tests >&2
23-
echo "**************************" >&2
24-
}
2519
$REALTIME && python3 -m pip install -r ./requirements-realtime.txt
26-
md5sum requirements.txt extras.txt requirements-realtime.txt > $1/checksums
20+
md5sum requirements.txt requirements-realtime.txt > $1/checksums
2721
}
2822

2923
if [[ "$VIRTUAL_ENV" != "" ]]

tests/channels/pjsip/subscriptions/presence/verify_bodies/verify_pidf/test-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ properties:
2222
version : 'v3.0'
2323
- python: 'twisted'
2424
- python: 'starpy'
25-
- python: 'yappcap'
25+
- python: 'scapy'
2626
- asterisk: 'res_pjsip'
2727
- asterisk: 'res_pjsip_exten_state'
2828
- asterisk: 'res_pjsip_pidf_body_generator'
@@ -47,6 +47,7 @@ test-modules:
4747
sipp-config:
4848
reactor-timeout: 30
4949
fail-on-any: True
50+
stop-after-scenarios: False
5051
test-iterations:
5152
-
5253
scenarios:

tests/channels/pjsip/subscriptions/presence/verify_bodies/verify_xpidf/test-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ properties:
2222
version : 'v3.0'
2323
- python: 'twisted'
2424
- python: 'starpy'
25-
- python: 'yappcap'
25+
- python: 'scapy'
2626
- asterisk: 'res_pjsip'
2727
- asterisk: 'res_pjsip_exten_state'
2828
- asterisk: 'res_pjsip_xpidf_body_generator'
@@ -47,6 +47,7 @@ test-modules:
4747
sipp-config:
4848
reactor-timeout: 30
4949
fail-on-any: True
50+
stop-after-scenarios: False
5051
test-iterations:
5152
-
5253
scenarios:

tests/channels/pjsip/subscriptions/rls/rls_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def log_packet(packet, write_packet_contents):
5252
"""Writes the contents of a SIP packet to the log.
5353
5454
Keyword Arguments:
55-
packet -- A yappcap.PcapPacket
55+
packet -- A PcapPacket
5656
write_packet_contents -- Whether or not to dump the contents of the
5757
packet to the log.
5858
"""

tests/channels/pjsip/transfers/attended_transfer/nominal/callee_local_direct_media/test-config.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,7 @@ properties:
105105
dependencies:
106106
- python : twisted
107107
- python : starpy
108-
- python : yappcap
109-
- python : pyxb
110108
- asterisk : res_pjsip
111-
- custom : rawsocket
112109
- app : sipp
113110
tags:
114111
- pjsip

0 commit comments

Comments
 (0)