static async Task ReadPcapAsync(string file, Action <MessageDirection, RfpIdentifier, ReadOnlyMemory <byte>, DateTimeOffset> messageCallback, CancellationToken cancellationToken) { using (var s = File.OpenRead(file)) { var pcapHeader = new byte[24]; var success = await FillBufferAsync(s, pcapHeader, cancellationToken).ConfigureAwait(false); if (!success) { return; } if (BinaryPrimitives.ReadUInt32BigEndian(pcapHeader) != 0xa1b2c3d4 || pcapHeader[23] != 0x01) { Console.WriteLine("Invalid pcap file"); return; } var packetHeader = new byte[16 + 54]; while (true) { success = await FillBufferAsync(s, packetHeader, cancellationToken).ConfigureAwait(false); if (!success) { return; } var direction = packetHeader[16] == 0x02 ? MessageDirection.ToOmm : MessageDirection.FromOmm; RfpIdentifier rfp; if (direction == MessageDirection.FromOmm) { rfp = new RfpIdentifier(packetHeader.AsMemory(16, 6)); } else { rfp = new RfpIdentifier(packetHeader.AsMemory(16 + 6, 6)); } var length = BinaryPrimitives.ReadUInt32BigEndian(packetHeader.AsSpan(12)); var data = new byte[length - 54]; success = await FillBufferAsync(s, data, cancellationToken).ConfigureAwait(false); if (!success) { return; } var seconds = BinaryPrimitives.ReadUInt32BigEndian(packetHeader); var milliseconds = BinaryPrimitives.ReadUInt32BigEndian(packetHeader.AsSpan(4)) / 1000; messageCallback(direction, rfp, data, DateTimeOffset.FromUnixTimeSeconds(seconds).AddMilliseconds(milliseconds)); } } }
private async Task InjectAsync(RfpIdentifier rfp, ushort handle, MediaToneMessage.Tone[] tones, CancellationToken cancellationToken) { var message = new MediaToneMessage(handle, MediaDirection.TxRx, 0, Array.Empty <MediaToneMessage.Tone>()); var data = new byte[message.Length]; message.Serialize(data); cancellationToken.ThrowIfCancellationRequested(); await WriteAsync(MessageDirection.ToRfp, 0, rfp, data, cancellationToken); message = new MediaToneMessage(handle, MediaDirection.TxRx, 0, tones); data = new byte[message.Length]; message.Serialize(data); cancellationToken.ThrowIfCancellationRequested(); await Task.Delay(1000, cancellationToken); await WriteAsync(MessageDirection.ToRfp, 0, rfp, data, cancellationToken); }
public async Task SubscribeAsync(ICollection <string> rfps, CancellationToken cancellationToken) { var filter = "0102 0000 0000 0000"; var mask = "ffff 0000 0000 0001"; foreach (var rfp in rfps) { await AddHandlerAsync(0, rfp, "ffffffffffff", filter, mask, cancellationToken); } await FinishHandshakeAsync(cancellationToken); var setBusy = HexEncoding.HexToByte("0102000402040001"); foreach (var rfp in rfps) { var rfpIdentifier = new RfpIdentifier(HexEncoding.HexToByte(rfp)); await WriteAsync(MessageDirection.ToRfp, 0, rfpIdentifier, setBusy, cancellationToken); } }
private bool ShouldHandle(RfpIdentifier identifier, ReadOnlyMemory <byte> data) { if (!identifier.Matches(Mac, MacMask.Span)) { return(false); } if (Filter.Length > data.Length) { return(false); } for (int i = 0; i < Filter.Length; i++) { var masked = data.Span[i] & FilterMask.Span[i]; if (masked != Filter.Span[i]) { return(false); } } return(true); }
public Subscription(ClientConnection client, CancellationTokenSource cancellationTokenSource, byte priority, Memory <byte> mac, ReadOnlyMemory <byte> macMask, Memory <byte> filter, ReadOnlyMemory <byte> filterMask, bool handle) { if (mac.Length != RfpIdentifier.Length) { throw new Exception("invalid mac length"); } if (macMask.Length != RfpIdentifier.Length) { throw new Exception("invalid mac mask length"); } if (filter.Length != filterMask.Length) { throw new Exception("filter and filter mask length must match"); } _cts = cancellationTokenSource; Client = client; Priority = priority; var masked = mac.Span; for (int i = 0; i < masked.Length; i++) { masked[i] &= macMask.Span[i]; } Mac = new RfpIdentifier(mac); MacMask = macMask; masked = filter.Span; for (int i = 0; i < masked.Length; i++) { masked[i] &= filterMask.Span[i]; } Filter = filter; FilterMask = filterMask; HandleMessage = handle; }
protected override async Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { if (_omm && direction == MessageDirection.ToOmm) { await WriteAsync(direction, messageId, rfp, data, cancellationToken).ConfigureAwait(false); return; } await WriteAsync(direction, messageId, rfp, ReadOnlyMemory <byte> .Empty, cancellationToken); await WriteAsync(_omm?MessageDirection.ToOmm : MessageDirection.ToRfp, 0, rfp, _ping, cancellationToken); }
protected override void WritePacketHeader(byte[] header, MessageDirection direction, uint messageId, RfpIdentifier rfp, ReadOnlyMemory <byte> data) { var span = header.AsSpan(); rfp.CopyTo(header); rfp.CopyTo(span.Slice(6)); if (direction == MessageDirection.FromOmm) { span[6] = 0x02; } else { span[0] = 0x02; } span[12] = 0x08; span = span.Slice(14); span[0] = 0x45; //version + IHL span[1] = 0x10; //tos BinaryPrimitives.WriteUInt16BigEndian(span.Slice(2), (ushort)(span.Length + data.Length)); //total length BinaryPrimitives.WriteUInt16BigEndian(span.Slice(4), (ushort)messageId); //identification BinaryPrimitives.WriteUInt16BigEndian(span.Slice(6), 0x4000); // flags span[8] = 0xff; //ttl span[9] = 6; //protocol if (direction == MessageDirection.ToOmm) { rfp.CopyTo(span.Slice(10)); //source address span[12] = 127; span[16] = 127; //destination address span[17] = 0; span[18] = 0; span[19] = 1; } else { rfp.CopyTo(span.Slice(14)); //destination address span[16] = 127; span[12] = 127; //source address span[13] = 0; span[14] = 0; span[15] = 1; } span = span.Slice(20); int seq; int ack; if (direction == MessageDirection.ToOmm) { seq = _rfpSequenceNumbers.AddOrUpdate(rfp, x => data.Length, (x, i) => i + data.Length); ack = _ommSequenceNumbers.GetOrAdd(rfp, 1); BinaryPrimitives.WriteUInt16BigEndian(span, 54321); //source port BinaryPrimitives.WriteUInt16BigEndian(span.Slice(2), 16321); //destination port } else { seq = _ommSequenceNumbers.AddOrUpdate(rfp, x => data.Length, (x, i) => i + data.Length); ack = _rfpSequenceNumbers.GetOrAdd(rfp, 1); BinaryPrimitives.WriteUInt16BigEndian(span, 16321); //source port BinaryPrimitives.WriteUInt16BigEndian(span.Slice(2), 54321); //destination port } BinaryPrimitives.WriteInt32BigEndian(span.Slice(4), seq - data.Length); BinaryPrimitives.WriteInt32BigEndian(span.Slice(8), ack); span[12] = 0x50; //data offset span[13] = 0b0001_0000; //flags span[14] = 0xff; //window size span[15] = 0xff; }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { return(Task.CompletedTask); }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { try { var ies = data.Slice(14); while (!ies.IsEmpty) { var current = ies.Span[0]; if (current > SignalType) { break; } if (current >= 128) { //fixed length if (current >= 224) { if (ies.Length < 2) { break; } if (current == SignalType) { ies.Span[1] = 0x41; Console.WriteLine("patched alerting pattern"); } ies = ies.Slice(2); } else { ies = ies.Slice(1); } } else { if (ies.Length < 2) { break; } var length = ies.Span[1]; ies = ies.Slice(2); if (current == (byte)NwkVariableLengthElementType.PortableIdentity) { //portable identity var ie = new NwkIePortableIdentity(ies); if (ie.IdentityType == NwkIePortableIdentity.PortableIdentityType.IPUI) { if (ie.Ipui.Put == NwkIePortableIdentity.IPUITypeCoding.O && ies.Length >= 5) { var span = ies.Slice(3).Span; var emc = (ushort)((span[0] & 0xf) << 12 | (span[1] << 4) | (span[2] >> 4)); if (!EMCs.Contains(emc)) { break; } } } } if (ies.Length < length) { break; } ies = ies.Slice(length); } } } catch (Exception ex) { Console.WriteLine(ex); } return(WriteAsync(direction, messageId, rfp, data, cancellationToken)); }
public RfpConnectionTracker(RfpIdentifier rfp, MacConnectionTracker tracker) { _tracker = tracker; Rfp = rfp; }
public RfpConnectionTracker(RfpIdentifier rfp) : this(rfp, new MacConnectionTracker()) { }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { try { var length = data.Span[15]; if (length == 8) { var iedata = data.Slice(16); var ie = new NwkIePortableIdentity(iedata); if (ie.IdentityType == NwkIePortableIdentity.PortableIdentityType.IPUI) { var ipui = ie.Ipui; if (ipui.Put == NwkIePortableIdentity.IPUITypeCoding.O) { if (direction == MessageDirection.FromOmm) { var emc = (ushort)(ipui.Number >> 20); if (EMCs.Contains(emc)) { Console.WriteLine(data.ToHex()); var span = iedata.Span; span[2] = (byte)(0x10 | (emc >> 12)); span[3] = (byte)(0xff & (emc >> 4)); span[4] = (byte)((0xf & emc) << 4); span[4] |= (byte)(ipui.Number >> 16 & 0xf); BinaryPrimitives.WriteUInt16BigEndian(span.Slice(5), (ushort)ipui.Number); span[7] = 0x00; Console.WriteLine($"shifted {data.ToHex()}"); } } else { var emc = (ushort)(ipui.Number >> 28); if (EMCs.Contains(emc)) { Console.WriteLine(data.ToHex()); //00000080 b0100301 400fdf var span = iedata.Span; span[2] = 0x10; span[3] = (byte)(emc >> 12); BinaryPrimitives.WriteUInt32BigEndian(span.Slice(4), (uint)(ipui.Number >> 8)); Console.WriteLine($"unshifted {data.ToHex()}"); } } } } } } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(data.ToHex()); } return(WriteAsync(direction, messageId, rfp, data, cancellationToken)); }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { throw new NotImplementedException(); }
protected override async Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { var packetheaderlength = PacketHeaderSize; var packetData = PreprocessData(data); var timestamp = DateTimeOffset.UtcNow; var header = new byte[16]; BinaryPrimitives.WriteUInt32BigEndian(header, (uint)timestamp.ToUnixTimeSeconds()); BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(4), (uint)timestamp.Millisecond * 1000); BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(8), (uint)(packetData.Length + packetheaderlength)); BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(12), (uint)(packetData.Length + packetheaderlength)); await _file.WriteAsync(header, cancellationToken).ConfigureAwait(false); header = new byte[packetheaderlength]; WritePacketHeader(header, direction, messageId, rfp, packetData); await _file.WriteAsync(header, cancellationToken).ConfigureAwait(false); await _file.WriteAsync(packetData, cancellationToken).ConfigureAwait(false); }
protected abstract void WritePacketHeader(byte[] header, MessageDirection direction, uint messageId, RfpIdentifier rfp, ReadOnlyMemory <byte> data);
static async Task Main(string[] args) { string socketname = "client.sock"; bool showHelp = false; string mac = null; bool omm = false; var options = new OptionSet { { "s|socket=", "socket path", x => socketname = x }, { "r|rfp=", "rfp MAC address", x => mac = x }, { "o|omm", "generate traffic to omm", x => omm = x != null }, { "h|help", "show help", x => showHelp = x != null }, }; try { if (options.Parse(args).Count > 0) { showHelp = true; } } catch (OptionException ex) { Console.Error.Write("rfpproxytraffic: "); Console.Error.WriteLine(ex.Message); Console.Error.WriteLine("Try 'dotnet rfpproxytraffic.dll --help' for more information"); return; } if (String.IsNullOrEmpty(mac)) { showHelp = true; } if (showHelp) { options.WriteOptionDescriptions(Console.Error); return; } try { using (var cts = new CancellationTokenSource()) using (var client = new TrafficClient(omm, socketname)) { Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); client.Stop(); }; client.Log += (s, e) => { Console.Write(e.Direction == LogDirection.Read ? "< " : "> "); Console.WriteLine(e.Message); }; var rfp = new RfpIdentifier(HexEncoding.HexToByte(mac)); if (omm) { await client.AddHandlerAsync(0, mac, "ffffffffffff", "00030008deadbeefbabefefe", "ffffffffffffffffffffffff", cts.Token); } else { await client.AddHandlerAsync(0, mac, "ffffffffffff", "010e0018ac1417010f", "ffffffffffffffff0f", cts.Token); } await client.FinishHandshakeAsync(cts.Token); if (omm) { await client.WriteAsync(MessageDirection.ToOmm, 0, rfp, HexEncoding.HexToByte("00030008deadbeefbabefefe"), cts.Token); } else { await client.WriteAsync(MessageDirection.ToRfp, 0, rfp, HexEncoding.HexToByte("010e000cac1417010f00000000000000"), cts.Token); } await client.RunAsync(cts.Token); } } catch (OperationCanceledException) { } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted) { } }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { Console.WriteLine("suppressed SYS_LED"); return(WriteAsync(direction, messageId, rfp, Array.Empty <byte>(), cancellationToken)); }
protected override Task OnMessageAsync(MessageDirection direction, uint messageId, RfpIdentifier rfp, Memory <byte> data, CancellationToken cancellationToken) { if (data.Length < 6) { return(Task.CompletedTask); } var hdl = BinaryPrimitives.ReadUInt16LittleEndian(data.Span.Slice(4)); if (data.Span[1] == 2) { if (data.Span[0] == 0) { //NACK if (direction == MessageDirection.ToOmm) { //suppress return(WriteAsync(direction, messageId, rfp, Memory <byte> .Empty, cancellationToken)); } } else { //MEDIA_CLOSE OnClose(hdl); } } else if (data.Span[1] == 9) { //MEDIA_DTMF return(OnDtmfAsync(rfp, hdl, data, cancellationToken)); } return(Task.CompletedTask); }
protected override void WritePacketHeader(byte[] header, MessageDirection direction, uint messageId, RfpIdentifier rfp, ReadOnlyMemory <byte> data) { rfp.CopyTo(header); rfp.CopyTo(header.AsSpan(6)); if (direction == MessageDirection.FromOmm) { header[6] = 0x02; } else { header[0] = 0x02; } header[12] = 0xa0; BinaryPrimitives.WriteUInt16BigEndian(header.AsSpan(14), (ushort)data.Length); header[16] = 0xba; header[17] = 0xbe; }
public void OnMessage(MessageDirection direction, RfpIdentifier rfp, ReadOnlyMemory <byte> data, DateTimeOffset timestamp) { if (data.IsEmpty) { return; } AaMiDeMessage message; string prefix; MacConnectionTracker reassembler; if (direction == MessageDirection.FromOmm) { reassembler = _ommTracker; prefix = "OMM:"; } else { reassembler = _rfpTracker; prefix = "RFP:"; } try { message = AaMiDeMessage.Create(data, reassembler.Get(rfp)); } catch (Exception ex) { Console.WriteLine($"{timestamp:yyyy/MM/dd HH:mm:ss.fff} {prefix}{rfp} Cannot parse {data.ToHex()}"); Console.WriteLine(ex); return; } if (message is DnmMessage dnm) { if (dnm.Payload is MacDisIndPayload || dnm.DnmType == DnmType.MacDisReq) { RfpConnectionTracker rfpTracker; if (direction == MessageDirection.FromOmm) { rfpTracker = _rfpTracker.Get(rfp); } else { rfpTracker = _ommTracker.Get(rfp); } var nwk = rfpTracker.Get(dnm.MCEI); nwk.Close(); } else if (dnm.Payload is MacConIndPayload macConInd) { RfpConnectionTracker rfpTracker; if (direction == MessageDirection.FromOmm) { rfpTracker = _rfpTracker.Get(rfp); } else { rfpTracker = _ommTracker.Get(rfp); } var nwk = rfpTracker.Get(dnm.MCEI); nwk.Open(macConInd); } } if (_unknown && !message.HasUnknown) { return; } Console.Write($"{timestamp:yyyy/MM/dd HH:mm:ss.fff} {prefix}{rfp} "); message.Log(Console.Out); Console.WriteLine(); if (_logRaw) { Console.Write("\t"); int i = 0; var span = data.Span; for (; i < span.Length - 4; i += 4) { Console.Write(span.Slice(i, 4).ToHex()); Console.Write(' '); } Console.WriteLine(span.Slice(i).ToHex()); } return; }