summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvuko <vuko@hackerspace.pl>2021-01-11 15:14:16 +0100
committervuko <vuko@hackerspace.pl>2021-01-11 15:14:16 +0100
commit2b939d21b3389458cbffd8095d95766afb334511 (patch)
tree98468d9842d54d8118f5a8ae20e1ad42c9f53ff5
parenta3dd788e301d30c84c8382f01f306d30dbe59da4 (diff)
downloadcheckinator-2b939d21b3389458cbffd8095d95766afb334511.tar.gz
checkinator-2b939d21b3389458cbffd8095d95766afb334511.tar.bz2
checkinator-2b939d21b3389458cbffd8095d95766afb334511.zip
get ip hw_address from tracker
-rw-r--r--at/tracker.proto12
-rw-r--r--at/tracker.py25
-rw-r--r--at/webapp.py25
3 files changed, 53 insertions, 9 deletions
diff --git a/at/tracker.proto b/at/tracker.proto
index 52e07df..42f1517 100644
--- a/at/tracker.proto
+++ b/at/tracker.proto
@@ -1,7 +1,11 @@
syntax = "proto3";
service DhcpTracker {
+ /* get list of clients detected in LAN network */
rpc GetClients (ClientsRequest) returns (DhcpClients) {}
+
+ /* get Layer 2 addess (MAC) for LAN ip address (v4 or v6) */
+ rpc GetHwAddr (HwAddrRequest) returns (HwAddr) {}
}
message ClientsRequest {
@@ -17,3 +21,11 @@ message DhcpClient {
message DhcpClients {
repeated DhcpClient clients = 1;
}
+
+message HwAddrRequest {
+ string ip_address = 1; // IPv4 or IPv6 address
+}
+
+message HwAddrResponse
+ optional bytes hw_address = 1; // MAC address
+}
diff --git a/at/tracker.py b/at/tracker.py
index efecbdd..a6a0e8e 100644
--- a/at/tracker.py
+++ b/at/tracker.py
@@ -2,10 +2,14 @@ from at.dhcp import DhcpdUpdater, DhcpLease
from pathlib import Path
import yaml
import grpc
+import json
+import re
+import subprocess
+import logging
from concurrent import futures
from datetime import datetime
-from .tracker_pb2 import DhcpClient, DhcpClients
+from .tracker_pb2 import DhcpClient, DhcpClients, HwAddr
from .tracker_pb2_grpc import DhcpTrackerServicer, add_DhcpTrackerServicer_to_server
import argparse
@@ -13,6 +17,8 @@ parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="output more info", action="store_true")
parser.add_argument("config", type=Path, help="input file")
+logging.basicConfig(level=logging.INFO)
+
def lease_to_client(lease: DhcpLease) -> DhcpClient:
return DhcpClient(
hw_address = bytes.fromhex(lease.hwaddr.replace(':', '')),
@@ -26,7 +32,7 @@ class DhcpTrackerServicer(DhcpTrackerServicer):
self._tracker = tracker
super().__init__(*args, **kwargs)
- def GetClients(self, request, context):
+ def _authorize(self, context):
auth = context.auth_context()
ctype = auth.get('transport_security_type', 'local')
print(ctype)
@@ -48,10 +54,25 @@ class DhcpTrackerServicer(DhcpTrackerServicer):
f"Unknown transport type: {ctype}"
)
+ def GetClients(self, request, context):
+ self._authorize(context)
+
clients = [
lease_to_client(c) for c in self._tracker.get_active_devices().values()]
return DhcpClients(clients = clients)
+ def GetHwAddr(self, request, context):
+ self._authorize(context)
+ ip_address = str(request.ip_address)
+ if not re.fullmatch('[0-9a-fA-F:.]*', ip_address):
+ raise ValueError(f'Invalid ip address: {ip_address!r}')
+ logging.info(f'running ip neigh on {ip_address}')
+ r = subprocess.run(['ip', '-json', 'neigh', 'show', ip_address], check=True, capture_output=True)
+ neighs = json.loads(r.stdout)
+ if neighs:
+ return HwAddrResponse(hw_address=bytes.fromhex(neighs[0]['lladdr'].replace(':', '')))
+ return HwAddr(hw_address=None)
+
def server():
args = parser.parse_args()
diff --git a/at/webapp.py b/at/webapp.py
index 3809c72..0c8bc0c 100644
--- a/at/webapp.py
+++ b/at/webapp.py
@@ -9,7 +9,7 @@ import ipaddress
from typing import Tuple, Optional, Dict
import grpc
-from at.tracker_pb2 import ClientsRequest
+from at.tracker_pb2 import ClientsRequest, HwAddrRequest
from at.tracker_pb2_grpc import DhcpTrackerStub
from at.dhcp import DhcpLease
from datetime import datetime
@@ -44,12 +44,13 @@ class DevicesApi:
}
def get_device(self, ip: str) -> Tuple[Optional[str], Optional[str]]:
- devices = self._api.GetClients(ClientsRequest())
- for device in devices.clients:
- if device.ip_address == ip:
- return (
- format_mac(device.hw_address), device.client_hostname
- )
+ hw_address = self._api.GetHwAddr(HwAddrRequest(ip_address=ip)).hw_address
+ if hw_address is not None:
+ devices = self._api.GetClients(ClientsRequest())
+ for device in devices.clients:
+ if device.hw_address == hw_address:
+ return format_mac(hw_address), device.client_hostname
+ return format_mac(hw_address), ""
address = ipaddress.ip_address(ip)
if isinstance(address, ipaddress.IPv6Address):
@@ -91,3 +92,13 @@ else:
raise Exception("no GRPC_TLS_ADDRESS or GRPC_UNIX_SOCKET set in config file")
app = at.web.app(Path(__file__).parent, DevicesApi(channel), config)
+
+def run_debug():
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--port", type=int, default=8080, help="http port")
+ parser.add_argument("--ip", type=str, default='127.0.0.1', help="http port")
+
+ args = parser.parse_args()
+
+ app.run(args.ip, args.port, debug=True)