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


Ignore:
Timestamp:
Oct 28, 2026, 9:32:30 AM (3 days ago)
Author:
stuerze
Message:

Some fixes from security point of view

Location:
trunk/BNC/tests/tools
Files:
4 edited

Legend:

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

    r11127 r11130  
    197197
    198198
     199def frame(payload):
     200    """RTCM3 frame (preamble, length, payload, CRC24Q) of a payload."""
     201    head = bytes([0xD3, (len(payload) >> 8) & 0x03, len(payload) & 0xFF])
     202    return head + payload + crc24q(head + payload).to_bytes(3, "big")
     203
     204
    199205def cmd_slice(args):
    200206    stations = set(args.stations.split(",")) if args.stations else None
     207    types = args.types.split(",") if args.types else None
     208    parsers = {}
    201209
    202210    def selected():
    … …  
    208216            if args.end and t >= args.end:
    209217                continue
     218            if types:
     219                # keep only the RTCM3 messages of the given types (or type prefixes)
     220                frames = parsers.setdefault(sta, Rtcm3Framer()).feed(data)
     221                kept = b"".join(frame(pl) for pl in frames
     222                                if any(msg_type(pl).startswith(tt) for tt in types))
     223                if not kept:
     224                    continue
     225                data = kept
    210226            yield t, sta, fmt, data
    211227
    … …  
    245261    p.add_argument("--end", help="ISO time, exclusive")
    246262    p.add_argument("--stations", help="comma separated staIDs to keep")
     263    p.add_argument("--types", help="comma separated RTCM3 message types or prefixes to keep, "
     264                                   "e.g. 1019,4076_02 (GPS ephemerides and IGS-SSR GPS messages)")
    247265    p.set_defaults(func=cmd_slice)
    248266
  • trunk/BNC/tests/tools/fakecaster.py

    r11127 r11130  
    1515additionally requires a client certificate signed by that CA. With --serve
    1616a GET request (BNC as Ntrip client) is answered with the RTCM bytes of the
    17 given raw file. Failed TLS handshakes are reported on stdout.
     17given raw file. With --reply an upload is answered with this text instead
     18of the 200 status (e.g. a rejection), and the connection is closed. Failed
     19TLS handshakes are reported on stdout.
    1820"""
    1921
    … …  
    5557        self.total = 0
    5658        self.handshakes = 0
     59        self.rejected = 0
    5760        self.served = 0
    5861
    … …  
    6770
    6871
    69 def serve(conn, store, timeout, tls=None, served=None):
     72def serve(conn, store, timeout, tls=None, served=None, reply=None):
    7073    conn.settimeout(timeout)
    7174    buf = b""
    … …  
    8992                         b"Content-Type: gnss/data\r\nConnection: close\r\n\r\n" + served)
    9093            store.served += len(served)
     94            return
     95        if reply is not None:
     96            conn.sendall(reply)
     97            store.rejected += 1
    9198            return
    9299        if header.startswith(b"SOURCE"):
    … …  
    127134    ap.add_argument("--tls-client-ca", help="require a client certificate of this CA")
    128135    ap.add_argument("--serve", help="raw file whose RTCM bytes are sent on GET")
     136    ap.add_argument("--reply", help="answer to uploads instead of 200 ('\\r\\n' escapes allowed)")
    129137    args = ap.parse_args()
    130138
    … …  
    136144            tls.verify_mode = ssl.CERT_REQUIRED
    137145            tls.load_verify_locations(args.tls_client_ca)
     146    reply = None
     147    if args.reply is not None:
     148        reply = args.reply.encode("latin-1").decode("unicode_escape").encode("latin-1")
    138149    served = None
    139150    if args.serve:
    … …  
    155166        except socket.timeout:
    156167            break
    157         t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served),
     168        t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served, reply),
    158169                             daemon=True)
    159170        t.start()
    … …  
    166177    if served is not None:
    167178        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)
    168181    return 0
    169182
  • trunk/BNC/tests/tools/mkcrafted.py

    r11125 r11130  
    66  CRAFT0IGS0  IGS-SSR VTEC (4076/201), decoded by SsrCorrIgs, followed by
    77              RTCM 1300/1301/1302 with 31-character names (BNC's RTCM scan
    8               lists them only for streams that also decode successfully)
     8              lists them only for streams that also decode successfully);
     9              in the first epoch also two RTCM 1033 (antenna and receiver
     10              descriptors): a complete one and one whose receiver descriptor
     11              length (200) runs beyond the end of the message
    912  CRAFT0RTC0  RTCM-SSR VTEC (1264), decoded by SsrCorrRtcm
    1013  CRAFT0NEW0  new RTCM-SSR metadata (60), not dispatched by BNC at present;
    … …  
    1215                - 7 entries (maximum), additional parameter of 40 and 0 bits
    1316                - 31 entries (5-bit count, more than META_MAXNUMENTRIES=7)
     17              and satellite antenna messages (DF+010-DF+021):
     18                - BDS (83): C01, C17, C33, C49, C64 (mask bits in all four
     19                  16-bit quarters of DF394), individual blocks
     20                - GPS (80): G01, G02, G32 sharing one block and one frequency
     21                  block; nadir angle corrections incl. the invalid value
    1422
    1523VTEC epochs (every 5 s):
    … …  
    2230by eye; the heights are 100 km * layer number.
    2331
     32With --rawfile, a raw file with hostile chunk headers is written instead
     33(test of the raw file reader, data/crafted_rawfile.raw):
     34  ../ESCAPE0  station ID with a path: RTCM-SSR VTEC whose .ssr file must be
     35              written inside the output directory
     36  CRAFT0RTC0  RTCM-SSR VTEC, 5 s later
     37  then a chunk header announcing 2000000000 bytes, which must be rejected
     38
    2439Usage: mkcrafted.py <out.raw>
     40       mkcrafted.py --rawfile <out.raw>
    2541"""
    2642
    … …  
    140156
    141157
     158def descriptors(strings, truncate=False):
     159    """RTCM 1033: antenna, setup ID, serial, receiver, firmware, serial."""
     160    w = BitWriter()
     161    w.u(1033, 12)
     162    w.u(0, 12)               # reference station ID
     163    ant, antser, rec, firm, recser = strings
     164    w.text(ant, 8)
     165    w.u(0, 8)                # antenna setup ID
     166    w.text(antser, 8)
     167    if truncate:
     168        w.u(200, 8)          # receiver descriptor length beyond the message
     169        for c in rec.encode("ascii"):
     170            w.u(c, 8)
     171    else:
     172        w.text(rec, 8)
     173        w.text(firm, 8)
     174        w.text(recser, 8)
     175    return frame(w.payload())
     176
     177
    142178def metadata(entries):
    143179    """entries: list of None (default model) or number of additional bits."""
    … …  
    163199
    164200
     201def antenna(msg, sats, shared, nadir):
     202    """Satellite antenna message; sats: PRNs (1..64) of the mask."""
     203    w = BitWriter()
     204    w.u(msg, 12)
     205    w.u(4711, 16)            # provider ID
     206    w.u(5, 6)                # satellite antenna IOD
     207    w.u(1, 1)                # phase center information
     208    w.u(0, 1)                # group delay information
     209    w.u(1, 1)                # nadir angle dependent corrections follow
     210    w.u(3, 5)                # maximum off-nadir angle: corrections 0..3 deg
     211    w.u(1, 4)                # range extension: 3 + 1 = 4 bits
     212    w.u(shared, 1)           # satellite set indicator
     213    mask = 0
     214    for prn in sats:
     215        mask |= 1 << (64 - prn)
     216    w.u(mask, 64)
     217    for n in range(1 if shared else len(sats)):
     218        w.u(shared, 1)       # frequency set indicator
     219        w.u(0b101000, 6)     # frequencies 0 and 2
     220        for f in range(1 if shared else 2):
     221            w.u(1, 1)        # nadir correction follows
     222            w.s(100 * n + 10 * f + 1, 12)    # mm
     223            for deg in range(4):
     224                w.s(nadir[(n + f + deg) % len(nadir)], 4)   # mm, -8: invalid
     225    return frame(w.payload())
     226
     227
     228def rawfile(path):
     229    chunks = []
     230    for i, sta in enumerate(["../ESCAPE0", "CRAFT0RTC0"]):
     231        t = T0 + datetime.timedelta(seconds=5 * i)
     232        chunks.append((t.isoformat(), sta, "RTCM_3", vtec_rtcm(t, [(2, 2)])))
     233    write_chunks(path, chunks)
     234    t = T0 + datetime.timedelta(seconds=10)
     235    with open(path, "ab") as o:
     236        o.write(("%s CRAFT0RTC0 RTCM_3 2000000000\n" % t.isoformat()).encode())
     237        o.write(vtec_rtcm(t, [(2, 2)]) + b"\n")
     238
     239
    165240def main():
     241    if len(sys.argv) == 3 and sys.argv[1] == "--rawfile":
     242        rawfile(sys.argv[2])
     243        return
    166244    if len(sys.argv) != 2:
    167245        sys.exit(__doc__)
    … …  
    175253        t = T0 + datetime.timedelta(seconds=5 * i)
    176254        stamp = t.isoformat()
    177         chunks.append((stamp, "CRAFT0IGS0", "RTCM_3", vtec_igs(t, layers)
    178                        + service_crs() + helmert() + rtcm_crs()))
     255        data = vtec_igs(t, layers) + service_crs() + helmert() + rtcm_crs()
     256        if i == 0:
     257            data += descriptors(["LEIAR25.R4      LEIT", "12345", "SEPT POLARX5",
     258                                 "5.5.0", "3001234"])
     259            data += descriptors(["TRUNCATED ANTENNA", "9", "RECEIVER", "", ""],
     260                                truncate=True)
     261        chunks.append((stamp, "CRAFT0IGS0", "RTCM_3", data))
    179262        chunks.append((stamp, "CRAFT0RTC0", "RTCM_3", vtec_rtcm(t, layers)))
    180263    stamp = (T0 + datetime.timedelta(seconds=15)).isoformat()
    181264    chunks.append((stamp, "CRAFT0NEW0", "RTCM_3",
    182                    metadata([40, 0] + [None] * 5) + metadata([None] * 31)))
     265                   metadata([40, 0] + [None] * 5) + metadata([None] * 31)
     266                   + antenna(83, [1, 17, 33, 49, 64], 0, [-7, 0, 7, 3])
     267                   + antenna(80, [1, 2, 32], 1, [5, -8, -1, 2])))
    183268    write_chunks(sys.argv[1], chunks)
    184269
  • trunk/BNC/tests/tools/ssr_harness.cpp

    r11127 r11130  
    77// reported by AddressSanitizer instead of silently corrupting the next member.
    88//
    9 // Every decoded VTEC (all formats) and metadata message (new RTCM-SSR) is
    10 // encoded again with the Make* function of the same class and decoded once
    11 // more; the result must be identical (exit code 1 otherwise).
     9// Every decoded VTEC (all formats), metadata and satellite antenna message
     10// (new RTCM-SSR) is encoded again with the Make* function of the same class
     11// and decoded once more; the result must be identical, for the antenna
     12// messages also the bytes of the frame (exit code 1 otherwise).
    1213//
    1314// Usage: ssr_harness <file>   (BNC raw file or plain RTCM3 byte stream)
    … …  
    9697  int irc = t1.decode(ssr, frame, size);
    9798  printf("  %-8s irc %3d", name, irc);
     99  SsrCorrRtcmNew* rtcmNew = dynamic_cast<SsrCorrRtcmNew*>(ssr);
    98100  if (irc >= 0 && t1.v->NumLayers) {
    99101    double sum = 0.0;
    … …  
    125127      }
    126128    }
    127     SsrCorrRtcmNew* rtcmNew = dynamic_cast<SsrCorrRtcmNew*>(ssr);
    128129    if (rtcmNew) {
    129130      char buffer[CLOCKORBIT_BUFFERSIZE];
    … …  
    134135      nFailed += !ok;
    135136    }
     137  }
     138  for (unsigned s = 0; rtcmNew && irc >= 0 && s < CLOCKORBIT_SATNUM; s++) {
     139    if (!t1.a->SatelliteMask[s]) {
     140      continue;
     141    }
     142    printf("  ANT type %u mask %016llx", t1.a->messageType[s],
     143           (unsigned long long)t1.a->SatelliteMask[s]);
     144    char buffer[CLOCKORBIT_BUFFERSIZE];
     145    size_t len = rtcmNew->MakeAntenna(t1.a, t1.a->messageType[s], buffer, sizeof(buffer));
     146    t_target t2;
     147    bool sameBytes = len == size && memcmp(buffer, frame, size) == 0;
     148    bool ok = len > 0 && t2.decode(ssr, (const unsigned char*)buffer, len) >= 0 &&
     149              memcmp(t1.a, t2.a, sizeof(*t1.a)) == 0;
     150    printf("  re-encoded: %s, %s", ok ? "identical" : "DIFFERENT",
     151           sameBytes ? "same bytes" : "OTHER BYTES");
     152    nFailed += !ok || !sameBytes;
    136153  }
    137154  printf("\n");
Note: See TracChangeset for help on using the changeset viewer.