esp32_bluetooth_classic_sni.../libs/scapy/contrib/cansocket_native.py
Matheus Eduardo Garbelini 86890704fd initial commit
todo: add documentation & wireshark dissector
2021-08-31 19:51:03 +08:00

123 lines
4.3 KiB
Python
Executable file

# This file is part of Scapy
# See http://www.secdev.org/projects/scapy for more information
# Copyright (C) Nils Weiss <nils@we155.de>
# This program is published under a GPLv2 license
# scapy.contrib.description = Native CANSocket
# scapy.contrib.status = loads
"""
NativeCANSocket.
"""
import struct
import socket
import time
from scapy.config import conf
from scapy.supersocket import SuperSocket
from scapy.error import Scapy_Exception, warning
from scapy.layers.can import CAN
from scapy.packet import Padding
from scapy.arch.linux import get_last_packet_timestamp
conf.contribs['NativeCANSocket'] = {'channel': "can0"}
CAN_FRAME_SIZE = 16
CAN_INV_FILTER = 0x20000000
class NativeCANSocket(SuperSocket):
desc = "read/write packets at a given CAN interface using PF_CAN sockets"
nonblocking_socket = True
def __init__(self, channel=None, receive_own_messages=False,
can_filters=None, remove_padding=True, basecls=CAN, **kwargs):
bustype = kwargs.pop("bustype", None)
if bustype and bustype != "socketcan":
warning("You created a NativeCANSocket. "
"If you're providing the argument 'bustype', please use "
"the correct one to achieve compatibility with python-can"
"/PythonCANSocket. \n'bustype=socketcan'")
self.basecls = basecls
self.remove_padding = remove_padding
self.channel = conf.contribs['NativeCANSocket']['channel'] if \
channel is None else channel
self.ins = socket.socket(socket.PF_CAN,
socket.SOCK_RAW,
socket.CAN_RAW)
try:
self.ins.setsockopt(socket.SOL_CAN_RAW,
socket.CAN_RAW_RECV_OWN_MSGS,
struct.pack("i", receive_own_messages))
except Exception as exception:
raise Scapy_Exception(
"Could not modify receive own messages (%s)", exception
)
if can_filters is None:
can_filters = [{
"can_id": 0,
"can_mask": 0
}]
can_filter_fmt = "={}I".format(2 * len(can_filters))
filter_data = []
for can_filter in can_filters:
filter_data.append(can_filter["can_id"])
filter_data.append(can_filter["can_mask"])
self.ins.setsockopt(socket.SOL_CAN_RAW,
socket.CAN_RAW_FILTER,
struct.pack(can_filter_fmt, *filter_data))
self.ins.bind((self.channel,))
self.outs = self.ins
def recv(self, x=CAN_FRAME_SIZE):
try:
pkt, sa_ll = self.ins.recvfrom(x)
except BlockingIOError: # noqa: F821
warning("Captured no data, socket in non-blocking mode.")
return None
except socket.timeout:
warning("Captured no data, socket read timed out.")
return None
except OSError:
# something bad happened (e.g. the interface went down)
warning("Captured no data.")
return None
# need to change the byte order of the first four bytes,
# required by the underlying Linux SocketCAN frame format
if not conf.contribs['CAN']['swap-bytes']:
pkt = struct.pack("<I12s", *struct.unpack(">I12s", pkt))
len = pkt[4]
canpkt = self.basecls(pkt[:len + 8])
canpkt.time = get_last_packet_timestamp(self.ins)
if self.remove_padding:
return canpkt
else:
return canpkt / Padding(pkt[len + 8:])
def send(self, x):
try:
if hasattr(x, "sent_time"):
x.sent_time = time.time()
# need to change the byte order of the first four bytes,
# required by the underlying Linux SocketCAN frame format
bs = bytes(x)
if not conf.contribs['CAN']['swap-bytes']:
bs = bs + b'\x00' * (CAN_FRAME_SIZE - len(bs))
bs = struct.pack("<I12s", *struct.unpack(">I12s", bs))
return SuperSocket.send(self, bs)
except socket.error as msg:
raise msg
def close(self):
self.ins.close()
CANSocket = NativeCANSocket