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

@@ -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()