fix formatting

This commit is contained in:
Kevin Hester
2021-02-26 15:47:52 +08:00
parent 5ff3fb2fe1
commit 3bbbead497
4 changed files with 166 additions and 91 deletions

View File

@@ -102,6 +102,8 @@ sudo usermod -a -G dialout <username>
## A note to developers of this lib
We use the visual-studio-code default python formatting conventions. So if you use that IDE you should be able to use "Format Document" and not generate unrelated diffs. If you use some other editor, please don't change formatting on lines you haven't changed.
If you need to build a new release you'll need:
```
apt install pandoc

View File

@@ -55,11 +55,19 @@ interface = meshtastic.SerialInterface()
"""
import socket
import pygatt
import google.protobuf.json_format
import serial, threading, logging, sys, random, traceback, time, base64, platform
from . import mesh_pb2, portnums_pb2, util
import serial
import threading
import logging
import sys
import random
import traceback
import time
import base64
import platform
import socket
from . import mesh_pb2, portnums_pb2, apponly_pb2, util
from pubsub import pub
from dotmap import DotMap
@@ -79,7 +87,8 @@ MY_CONFIG_ID = 42
format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
"""
OUR_APP_VERSION = 20200
OUR_APP_VERSION = 20200
def catchAndIgnore(reason, closure):
"""Call a closure but if it throws an excpetion print it and continue"""
@@ -88,6 +97,7 @@ def catchAndIgnore(reason, closure):
except BaseException as ex:
logging.error(f"Exception thrown in {reason}: {ex}")
class MeshInterface:
"""Interface class for meshtastic devices
@@ -108,7 +118,7 @@ class MeshInterface:
self.nodes = None # FIXME
self.isConnected = threading.Event()
self.noProto = noProto
random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it
random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it
self.currentPacketId = random.randint(0, 0xffffffff)
self._startConfig()
@@ -117,7 +127,8 @@ class MeshInterface:
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None and exc_value is not None:
logging.error(f'An exception of type {exc_type} with value {exc_value} has occurred')
logging.error(
f'An exception of type {exc_type} with value {exc_value} has occurred')
if traceback is not None:
logging.error(f'Traceback: {traceback}')
self.close()
@@ -265,6 +276,7 @@ class MeshInterface:
"""Set device owner name"""
nChars = 3
minChars = 2
fixme("update for 1.2")
if long_name is not None:
long_name = long_name.strip()
if short_name is None:
@@ -292,27 +304,30 @@ class MeshInterface:
def channelURL(self):
"""The sharable URL that describes the current channel
"""
bytes = self.radioConfig.channel_settings.SerializeToString()
channelSet = apponly_pb2.ChannelSet()
fixme("fill channelSet from self.channels")
bytes = channelSet.SerializeToString()
s = base64.urlsafe_b64encode(bytes).decode('ascii')
return f"https://www.meshtastic.org/c/#{s}"
def setURL(self, url, write=True):
def setURL(self, url):
"""Set mesh network URL"""
if self.radioConfig == None:
raise Exception("No RadioConfig has been read")
# URLs are of the form https://www.meshtastic.org/c/#{base64_channel_settings}
# URLs are of the form https://www.meshtastic.org/c/#{base64_channel_set}
# Split on '/#' to find the base64 encoded channel settings
splitURL = url.split("/#")
decodedURL = base64.urlsafe_b64decode(splitURL[-1])
self.radioConfig.channel_settings.ParseFromString(decodedURL)
if write:
self.writeConfig()
channelSet = apponly_pb2.ChannelSet()
channelSet.ParseFromString(decodedURL)
fixme("set self.channels")
self.writeChannels()
def _waitConnected(self):
"""Block until the initial node db download is complete, or timeout
and raise an exception"""
if not self.isConnected.wait(5.0): # timeout after 5 seconds
if not self.isConnected.wait(5.0): # timeout after 5 seconds
raise Exception("Timed out waiting for connection completion")
def _generatePacketId(self):
@@ -326,13 +341,15 @@ class MeshInterface:
def _disconnected(self):
"""Called by subclasses to tell clients this interface has disconnected"""
self.isConnected.clear()
catchAndIgnore("disconnection publish", lambda: pub.sendMessage("meshtastic.connection.lost", interface=self))
catchAndIgnore("disconnection publish", lambda: pub.sendMessage(
"meshtastic.connection.lost", interface=self))
def _connected(self):
"""Called by this class to tell clients we are now fully connected to a node
"""
self.isConnected.set()
catchAndIgnore("connection publish", lambda: pub.sendMessage("meshtastic.connection.established", interface=self))
catchAndIgnore("connection publish", lambda: pub.sendMessage(
"meshtastic.connection.established", interface=self))
def _startConfig(self):
"""Start device packets flowing"""
@@ -348,7 +365,8 @@ class MeshInterface:
def _sendToRadio(self, toRadio):
"""Send a ToRadio protobuf to the device"""
if self.noProto:
logging.warn(f"Not sending packet because protocol use is disabled by noProto")
logging.warn(
f"Not sending packet because protocol use is disabled by noProto")
else:
logging.debug(f"Sending toRadio: {toRadio}")
self._sendToRadioImpl(toRadio)
@@ -357,6 +375,15 @@ class MeshInterface:
"""Send a ToRadio protobuf to the device"""
logging.error(f"Subclass must provide toradio: {toRadio}")
def _handleConfigComplete(self):
"""
Done with initial config messages, now send regular MeshPackets to ask for settings and channels
"""
self._requestSettings()
self._requestChannels()
# FIXME, the following should only be called after we have settings and channels
self._connected() # Tell everone else we are ready to go
def _handleFromRadio(self, fromRadioBytes):
"""
Handle a packet that arrived from the radio(update model and publish events)
@@ -383,10 +410,11 @@ class MeshInterface:
self.nodesByNum[node["num"]] = node
if "user" in node: # Some nodes might not have user/ids assigned yet
self.nodes[node["user"]["id"]] = node
pub.sendMessage("meshtastic.node.updated", node=node, interface=self)
pub.sendMessage("meshtastic.node.updated",
node=node, interface=self)
elif fromRadio.config_complete_id == MY_CONFIG_ID:
# we ignore the config_complete_id, it is unneeded for our stream API fromRadio.config_complete_id
self._connected()
self._handleConfigComplete()
elif fromRadio.HasField("packet"):
self._handlePacketFromRadio(fromRadio.packet)
elif fromRadio.rebooted:
@@ -465,7 +493,8 @@ class MeshInterface:
# UNKNOWN_APP is the default protobuf portnum value, and therefore if not set it will not be populated at all
# to make API usage easier, set it to prevent confusion
if not "portnum" in asDict["decoded"]:
asDict["decoded"]["portnum"] = portnums_pb2.PortNum.Name(portnums_pb2.PortNum.UNKNOWN_APP)
asDict["decoded"]["portnum"] = portnums_pb2.PortNum.Name(
portnums_pb2.PortNum.UNKNOWN_APP)
portnum = asDict["decoded"]["portnum"]
@@ -482,7 +511,8 @@ class MeshInterface:
# Usually btw this problem is caused by apps sending binary data but setting the payload type to
# text.
try:
asDict["decoded"]["text"] = meshPacket.decoded.payload.decode("utf-8")
asDict["decoded"]["text"] = meshPacket.decoded.payload.decode(
"utf-8")
except Exception as ex:
logging.error(f"Malformatted utf8 in text message: {ex}")
@@ -511,7 +541,8 @@ class MeshInterface:
self.nodes[u["id"]] = n
logging.debug(f"Publishing topic {topic}")
catchAndIgnore(f"publishing {topic}", lambda: pub.sendMessage(topic, packet=asDict, interface=self))
catchAndIgnore(f"publishing {topic}", lambda: pub.sendMessage(
topic, packet=asDict, interface=self))
# Our standard BLE characteristics
@@ -600,7 +631,7 @@ class StreamInterface(MeshInterface):
time.sleep(0.1) # wait 100ms to give device time to start running
self._rxThread.start()
if not self.noProto: # Wait for the db download if using the protocol
if not self.noProto: # Wait for the db download if using the protocol
self._waitConnected()
def _disconnected(self):
@@ -686,13 +717,16 @@ class StreamInterface(MeshInterface):
# logging.debug(f"timeout")
pass
except serial.SerialException as ex:
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.warn(f"Meshtastic serial port disconnected, disconnecting... {ex}")
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.warn(
f"Meshtastic serial port disconnected, disconnecting... {ex}")
except OSError as ex:
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.error(f"Unexpected OSError, terminating meshtastic reader... {ex}")
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.error(
f"Unexpected OSError, terminating meshtastic reader... {ex}")
except Exception as ex:
logging.error(f"Unexpected exception, terminating meshtastic reader... {ex}")
logging.error(
f"Unexpected exception, terminating meshtastic reader... {ex}")
finally:
logging.debug("reader is exiting")
self._disconnected()
@@ -740,6 +774,7 @@ class SerialInterface(StreamInterface):
StreamInterface.__init__(
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
class TCPInterface(StreamInterface):
"""Interface class for meshtastic devices over a TCP link"""
@@ -766,9 +801,9 @@ class TCPInterface(StreamInterface):
def close(self):
"""Close a connection to the device"""
logging.debug("Closing TCP stream")
# Sometimes the socket read might be blocked in the reader thread. Therefore we force the shutdown by closing
# Sometimes the socket read might be blocked in the reader thread. Therefore we force the shutdown by closing
# the socket here
self._wantExit = True
self._wantExit = True
if not self.socket is None:
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()

View File

@@ -1,6 +1,11 @@
#!python3
import argparse, platform, logging, sys, codecs, base64
import argparse
import platform
import logging
import sys
import codecs
import base64
from . import SerialInterface, TCPInterface, BLEInterface, test, remote_hardware
from pubsub import pub
from . import mesh_pb2, portnums_pb2
@@ -20,6 +25,7 @@ args = None
"""The parser for arguments"""
parser = argparse.ArgumentParser()
def onReceive(packet, interface):
"""Callback invoked when a packet arrives"""
logging.debug(f"Received: {packet}")
@@ -54,6 +60,7 @@ def onConnection(interface, topic=pub.AUTO_TOPIC):
trueTerms = {"t", "true", "yes"}
falseTerms = {"f", "false", "no"}
def fromStr(valstr):
"""try to parse as int, float or bool (and fallback to a string as last resort)
@@ -63,7 +70,8 @@ def fromStr(valstr):
valstr (string): A user provided string
"""
if(valstr.startswith('0x')):
val = bytes.fromhex(valstr[2:]) # if needed convert to string with asBytes.decode('utf-8')
# if needed convert to string with asBytes.decode('utf-8')
val = bytes.fromhex(valstr[2:])
elif valstr in trueTerms:
val = True
elif valstr in falseTerms:
@@ -94,7 +102,7 @@ def setRouter(interface, on):
# FIXME as of 1.1.24 of the device code, the following is all deprecated. After that release
# has been out a while, just set is_router and warn the user about deprecation
#
#
prefs.is_low_power = True
prefs.gps_operation = mesh_pb2.GpsOpMobile
@@ -135,17 +143,21 @@ def setRouter(interface, on):
prefs.gps_update_interval = 0
#Returns formatted value
# Returns formatted value
def formatFloat(value, formatStr="{:.2f}", unit="", default="N/A"):
return formatStr.format(value)+unit if value else default
#Returns Last Heard Time in human readable format
# Returns Last Heard Time in human readable format
def getLH(ts, default="N/A"):
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else default
#Print Nodes
# Print Nodes
def printNodes(nodes):
#Create the table and define the structure
# Create the table and define the structure
table = EasyTable("Nodes")
table.setCorners("/", "\\", "\\", "/")
table.setOuterStructure("|", "-")
@@ -153,19 +165,20 @@ def printNodes(nodes):
tableData = []
for node in nodes:
#aux var to get not defined keys
LH= getLH(node['position'].get("time"))
lat=formatFloat(node['position'].get("latitude"), "{:.4f}", "°")
lon=formatFloat(node['position'].get("longitude"), "{:.4f}", "°")
alt=formatFloat(node['position'].get("altitude"), "{:.0f}", " m")
batt=formatFloat(node['position'].get("batteryLevel"), "{:.2f}", "%")
snr=formatFloat(node.get("snr"), "{:.2f}", " dB")
tableData.append({"User":node['user']['longName'],
"Position":"Lat:"+lat+", Lon:"+lon+", Alt:"+alt,
"Battery":batt, "SNR":snr, "LastHeard":LH})
# aux var to get not defined keys
LH = getLH(node['position'].get("time"))
lat = formatFloat(node['position'].get("latitude"), "{:.4f}", "°")
lon = formatFloat(node['position'].get("longitude"), "{:.4f}", "°")
alt = formatFloat(node['position'].get("altitude"), "{:.0f}", " m")
batt = formatFloat(node['position'].get("batteryLevel"), "{:.2f}", "%")
snr = formatFloat(node.get("snr"), "{:.2f}", " dB")
tableData.append({"User": node['user']['longName'],
"Position": "Lat:"+lat+", Lon:"+lon+", Alt:"+alt,
"Battery": batt, "SNR": snr, "LastHeard": LH})
table.setData(tableData)
table.displayTable()
def onConnected(interface):
"""Callback invoked when we connect to a radio"""
closeNow = False # Should we drop the connection after we finish?
@@ -227,7 +240,8 @@ def onConnected(interface):
for wrpair in (args.gpiowrb or []):
bitmask |= 1 << int(wrpair[0])
bitval |= int(wrpair[1]) << int(wrpair[0])
print(f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
print(
f"Writing GPIO mask 0x{bitmask:x} with value 0x{bitval:x} to {args.dest}")
rhc.writeGPIOs(args.dest, bitmask, bitval)
if args.gpiord:
@@ -238,10 +252,10 @@ def onConnected(interface):
if args.gpiowatch:
bitmask = int(args.gpiowatch)
print(f"Watching GPIO mask 0x{bitmask:x} from {args.dest}")
rhc.watchGPIOs(args.dest, bitmask)
rhc.watchGPIOs(args.dest, bitmask)
if args.set or args.setstr or args.setchan or args.setch_longslow or args.setch_shortfast \
or args.seturl or args.router != None:
or args.seturl or args.router != None:
closeNow = True
def setPref(attributes, name, valStr):
@@ -263,7 +277,7 @@ def onConnected(interface):
"""Set one of the simple modem_config only based channels"""
ch = mesh_pb2.ChannelSettings()
ch.modem_config = modem_config
ch.psk = bytes([1]) # Use default channel psk 1
ch.psk = bytes([1]) # Use default channel psk 1
interface.radioConfig.channel_settings.CopyFrom(ch)
if args.router != None:
@@ -280,10 +294,12 @@ def onConnected(interface):
# handle the simple channel set commands
if args.setch_longslow:
setSimpleChannel(mesh_pb2.ChannelSettings.ModemConfig.Bw125Cr48Sf4096)
setSimpleChannel(
mesh_pb2.ChannelSettings.ModemConfig.Bw125Cr48Sf4096)
if args.setch_shortfast:
setSimpleChannel(mesh_pb2.ChannelSettings.ModemConfig.Bw500Cr45Sf128)
setSimpleChannel(
mesh_pb2.ChannelSettings.ModemConfig.Bw500Cr45Sf128)
# Handle the channel settings
for pref in (args.setchan or []):
@@ -316,9 +332,10 @@ def onConnected(interface):
url = pyqrcode.create(interface.channelURL)
print(url.terminal())
if have_tunnel and args.tunnel :
if have_tunnel and args.tunnel:
from . import tunnel
closeNow = False # Even if others said we could close, stay open if the user asked for a tunnel
# Even if others said we could close, stay open if the user asked for a tunnel
closeNow = False
tunnel.Tunnel(interface, subnet=args.tunnel_net)
except Exception as ex:
@@ -328,6 +345,7 @@ def onConnected(interface):
if (not args.seriallog) and closeNow:
interface.close() # after running command then exit
def onNode(node):
"""Callback invoked when the node DB changes"""
print(f"Node changed: {node}")
@@ -383,6 +401,7 @@ def common():
client = SerialInterface(
args.port, debugOut=logfile, noProto=args.noproto)
def initParser():
global parser, args
@@ -403,7 +422,7 @@ def initParser():
parser.add_argument("--info", help="Read and display the radio config information",
action="store_true")
parser.add_argument("--nodes", help="Print Node List in a pretty formatted table",
parser.add_argument("--nodes", help="Print Node List in a pretty formatted table",
action="store_true")
parser.add_argument("--qr", help="Display the QR code that corresponds to the current channel",
@@ -439,7 +458,7 @@ def initParser():
parser.add_argument(
"--sendping", help="Send a ping message (which requests a reply)", action="store_true")
#parser.add_argument(
# parser.add_argument(
# "--repeat", help="Normally the send commands send only one message, use this option to request repeated sends")
parser.add_argument(
@@ -486,21 +505,24 @@ def initParser():
if have_tunnel:
parser.add_argument('--tunnel',
action='store_true', help="Create a TUN tunnel device for forwarding IP packets over the mesh")
action='store_true', help="Create a TUN tunnel device for forwarding IP packets over the mesh")
parser.add_argument(
"--subnet", dest='tunnel_net', help="Read from a GPIO mask", default=None)
parser.set_defaults(router=None)
parser.add_argument('--version', action='version', version=f"{pkg_resources.require('meshtastic')[0].version}")
parser.add_argument('--version', action='version',
version=f"{pkg_resources.require('meshtastic')[0].version}")
args = parser.parse_args()
def main():
"""Perform command line meshtastic operations"""
initParser()
common()
def tunnelMain():
"""Run a meshtastic IP tunnel"""
global args
@@ -508,5 +530,6 @@ def tunnelMain():
args.tunnel = True
common()
if __name__ == "__main__":
main()

View File

@@ -6,7 +6,7 @@
# sudo bin/run.sh --port /dev/ttyUSB0 --setch-shortfast
# sudo bin/run.sh --port /dev/ttyUSB0 --tunnel --debug
# ssh -Y root@192.168.10.151 (or dietpi), default password p
# ncat -e /bin/cat -k -u -l 1235
# ncat -e /bin/cat -k -u -l 1235
# ncat -u 10.115.64.152 1235
# ping -c 1 -W 20 10.115.64.152
# ping -i 30 -W 30 10.115.64.152
@@ -15,7 +15,8 @@
from . import portnums_pb2
from pubsub import pub
import logging, threading
import logging
import threading
# A new non standard log level that is lower level than DEBUG
LOG_TRACE = 5
@@ -26,8 +27,8 @@ tunnelInstance = None
"""A list of chatty UDP services we should never accidentally
forward to our slow network"""
udpBlacklist = {
1900, # SSDP
5353, # multicast DNS
1900, # SSDP
5353, # multicast DNS
}
"""A list of TCP services to block"""
@@ -35,31 +36,36 @@ tcpBlacklist = {}
"""A list of protocols we ignore"""
protocolBlacklist = {
0x02, # IGMP
0x80, # Service-Specific Connection-Oriented Protocol in a Multilink and Connectionless Environment
0x02, # IGMP
0x80, # Service-Specific Connection-Oriented Protocol in a Multilink and Connectionless Environment
}
def hexstr(barray):
"""Print a string of hex digits"""
return ":".join('{:02x}'.format(x) for x in barray)
def ipstr(barray):
"""Print a string of ip digits"""
return ".".join('{}'.format(x) for x in barray)
def readnet_u16(p, offset):
"""Read big endian u16 (network byte order)"""
return p[offset] * 256 + p[offset + 1]
def onTunnelReceive(packet, interface):
"""Callback for received tunneled messages from mesh
FIXME figure out how to do closures with methods in python"""
tunnelInstance.onReceive(packet)
class Tunnel:
"""A TUN based IP tunnel over meshtastic"""
def __init__(self, iface, subnet=None, netmask="255.255.0.0"):
"""
Constructor
@@ -77,7 +83,8 @@ class Tunnel:
global tunnelInstance
tunnelInstance = self
logging.info("Starting IP to mesh tunnel (you must be root for this *pre-alpha* feature to work). Mesh members:")
logging.info(
"Starting IP to mesh tunnel (you must be root for this *pre-alpha* feature to work). Mesh members:")
pub.subscribe(onTunnelReceive, "meshtastic.receive.data.IP_TUNNEL_APP")
myAddr = self._nodeNumToIp(self.iface.myInfo.my_node_num)
@@ -85,24 +92,26 @@ class Tunnel:
for node in self.iface.nodes.values():
nodeId = node["user"]["id"]
ip = self._nodeNumToIp(node["num"])
logging.info(f"Node { nodeId } has IP address { ip }")
logging.info(f"Node { nodeId } has IP address { ip }")
logging.debug("creating TUN device with MTU=200")
# FIXME - figure out real max MTU, it should be 240 - the overhead bytes for SubPacket and Data
from pytap2 import TapDevice
self.tun = TapDevice(name="mesh")
self.tun.up()
self.tun.ifconfig(address=myAddr,netmask=netmask,mtu=200)
self.tun.ifconfig(address=myAddr, netmask=netmask, mtu=200)
logging.debug(f"starting TUN reader, our IP address is {myAddr}")
self._rxThread = threading.Thread(target=self.__tunReader, args=(), daemon=True)
self._rxThread = threading.Thread(
target=self.__tunReader, args=(), daemon=True)
self._rxThread.start()
def onReceive(self, packet):
p = packet["decoded"]["data"]["payload"]
p = packet["decoded"]["payload"]
if packet["from"] == self.iface.myInfo.my_node_num:
logging.debug("Ignoring message we sent")
else:
logging.debug(f"Received mesh tunnel message type={type(p)} len={len(p)}")
logging.debug(
f"Received mesh tunnel message type={type(p)} len={len(p)}")
# we don't really need to check for filtering here (sender should have checked), but this provides
# useful debug printing on types of packets received
if not self._shouldFilterPacket(p):
@@ -114,36 +123,43 @@ class Tunnel:
srcaddr = p[12:16]
destAddr = p[16:20]
subheader = 20
ignore = False # Assume we will be forwarding the packet
ignore = False # Assume we will be forwarding the packet
if protocol in protocolBlacklist:
ignore = True
logging.log(LOG_TRACE, f"Ignoring blacklisted protocol 0x{protocol:02x}")
elif protocol == 0x01: # ICMP
logging.log(
LOG_TRACE, f"Ignoring blacklisted protocol 0x{protocol:02x}")
elif protocol == 0x01: # ICMP
icmpType = p[20]
icmpCode = p[21]
checksum = p[22:24]
logging.debug(f"forwarding ICMP message src={ipstr(srcaddr)}, dest={ipstr(destAddr)}, type={icmpType}, code={icmpCode}, checksum={checksum}")
logging.debug(
f"forwarding ICMP message src={ipstr(srcaddr)}, dest={ipstr(destAddr)}, type={icmpType}, code={icmpCode}, checksum={checksum}")
# reply to pings (swap src and dest but keep rest of packet unchanged)
#pingback = p[:12]+p[16:20]+p[12:16]+p[20:]
#tap.write(pingback)
elif protocol == 0x11: # UDP
# tap.write(pingback)
elif protocol == 0x11: # UDP
srcport = readnet_u16(p, subheader)
destport = readnet_u16(p, subheader + 2)
if destport in udpBlacklist:
ignore = True
logging.log(LOG_TRACE, f"ignoring blacklisted UDP port {destport}")
logging.log(
LOG_TRACE, f"ignoring blacklisted UDP port {destport}")
else:
logging.debug(f"forwarding udp srcport={srcport}, destport={destport}")
elif protocol == 0x06: # TCP
logging.debug(
f"forwarding udp srcport={srcport}, destport={destport}")
elif protocol == 0x06: # TCP
srcport = readnet_u16(p, subheader)
destport = readnet_u16(p, subheader + 2)
if destport in tcpBlacklist:
ignore = True
logging.log(LOG_TRACE, f"ignoring blacklisted TCP port {destport}")
logging.log(
LOG_TRACE, f"ignoring blacklisted TCP port {destport}")
else:
logging.debug(f"forwarding tcp srcport={srcport}, destport={destport}")
logging.debug(
f"forwarding tcp srcport={srcport}, destport={destport}")
else:
logging.warning(f"forwarding unexpected protocol 0x{protocol:02x}, src={ipstr(srcaddr)}, dest={ipstr(destAddr)}")
logging.warning(
f"forwarding unexpected protocol 0x{protocol:02x}, src={ipstr(srcaddr)}, dest={ipstr(destAddr)}")
return ignore
@@ -179,14 +195,13 @@ class Tunnel:
"""Forward the provided IP packet into the mesh"""
nodeId = self._ipToNodeId(destAddr)
if nodeId is not None:
logging.debug(f"Forwarding packet bytelen={len(p)} dest={ipstr(destAddr)}, destNode={nodeId}")
self.iface.sendData(p, nodeId, portnums_pb2.IP_TUNNEL_APP, wantAck = False)
logging.debug(
f"Forwarding packet bytelen={len(p)} dest={ipstr(destAddr)}, destNode={nodeId}")
self.iface.sendData(
p, nodeId, portnums_pb2.IP_TUNNEL_APP, wantAck=False)
else:
logging.warning(f"Dropping packet because no node found for destIP={ipstr(destAddr)}")
logging.warning(
f"Dropping packet because no node found for destIP={ipstr(destAddr)}")
def close(self):
self.tun.close()