Changeset 11153 in ntrip for trunk/BNC/tests/tools


Ignore:
Timestamp:
Oct 31, 2026, 11:50:15 PM (10 days ago)
Author:
stuerze
Message:

Credentials files are implemented, with existing configs keep working unchanged

Location:
trunk/BNC/tests/tools
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/tests/tools/fakecaster.py

    r11130 r11153  
    1616a GET request (BNC as Ntrip client) is answered with the RTCM bytes of the
    1717given raw file. With --reply an upload is answered with this text instead
    18 of the 200 status (e.g. a rejection), and the connection is closed. Failed
     18of the 200 status (e.g. a rejection), and the connection is closed. With
     19--auth user:password (repeatable, ':password' for an Ntrip 1 upload) only
     20these credentials are accepted, others get 401 / 'ERROR - Bad Password'.
     21The user received ("-" without user, "none" without credentials) and failed
    1922TLS handshakes are reported on stdout.
    2023"""
    2124
    2225import argparse
     26import base64
    2327import os
    2428import socket
    … …  
    7074
    7175
    72 def serve(conn, store, timeout, tls=None, served=None, reply=None):
     76def credentials(header):
     77    """(user, password) of a request header, None without credentials."""
     78    lines = header.split(b"\r\n")
     79    if lines[0].startswith(b"SOURCE"):
     80        parts = lines[0].split(b" ")
     81        return "", parts[1].decode("latin-1") if len(parts) > 1 else ""
     82    for line in lines[1:]:
     83        key, _, value = line.partition(b":")
     84        value = value.strip()
     85        if key.strip().lower() == b"authorization" and value.lower().startswith(b"basic "):
     86            user, _, password = base64.b64decode(value[6:]).decode("latin-1").partition(":")
     87            return user, password
     88    return None
     89
     90
     91def serve(conn, store, timeout, tls=None, served=None, reply=None, auth=None):
    7392    conn.settimeout(timeout)
    7493    buf = b""
    … …  
    88107        header, _, pending = buf.partition(b"\r\n\r\n")
    89108        chunked = b"chunked" in header.lower()
     109        cred = credentials(header)
     110        ok = auth is None or cred in auth
     111        print("auth %s %s" % ("none" if cred is None else (cred[0] or "-"),
     112                              "accepted" if ok else "rejected"), flush=True)
     113        if not ok:
     114            conn.sendall(b"ERROR - Bad Password\r\n" if header.startswith(b"SOURCE")
     115                         else b"HTTP/1.1 401 Unauthorized\r\n\r\n")
     116            store.rejected += 1
     117            return
    90118        if header.startswith(b"GET") and served is not None:
    91             conn.sendall(b"HTTP/1.1 200 OK\r\nNtrip-Version: Ntrip/2.0\r\n"
    92                          b"Content-Type: gnss/data\r\nConnection: close\r\n\r\n" + served)
     119            if b"ntrip-version" in header.lower():
     120                conn.sendall(b"HTTP/1.1 200 OK\r\nNtrip-Version: Ntrip/2.0\r\n"
     121                             b"Content-Type: gnss/data\r\nConnection: close\r\n\r\n" + served)
     122            else:  # Ntrip 1
     123                conn.sendall(b"ICY 200 OK\r\n\r\n" + served)
    93124            store.served += len(served)
    94125            return
    … …  
    134165    ap.add_argument("--tls-client-ca", help="require a client certificate of this CA")
    135166    ap.add_argument("--serve", help="raw file whose RTCM bytes are sent on GET")
     167    ap.add_argument("--auth", action="append",
     168                    help="accepted user:password (repeatable), others rejected")
    136169    ap.add_argument("--reply", help="answer to uploads instead of 200 ('\\r\\n' escapes allowed)")
    137170    args = ap.parse_args()
    … …  
    147180    if args.reply is not None:
    148181        reply = args.reply.encode("latin-1").decode("unicode_escape").encode("latin-1")
     182    auth = None
     183    if args.auth:
     184        auth = [tuple(a.split(":", 1)) for a in args.auth]
    149185    served = None
    150186    if args.serve:
    … …  
    166202        except socket.timeout:
    167203            break
    168         t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served, reply),
     204        t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served, reply, auth),
    169205                             daemon=True)
    170206        t.start()
    … …  
    177213    if served is not None:
    178214        print("served %d bytes" % store.served, flush=True)
    179     if reply is not None:
    180         print("%d upload(s) answered with --reply" % store.rejected, flush=True)
     215    if reply is not None or auth is not None:
     216        print("%d connection(s) rejected" % store.rejected, flush=True)
    181217    return 0
    182218
Note: See TracChangeset for help on using the changeset viewer.