Search code examples
node.jsipwiresharkraw-socketstshark

Node.JS and raw-socket doesn't seem to respect source IP


I'm testing Node.JS and raw-socket for sending out custom packets. It seems to work fine, however, it doesn't respect source IP.

This is my example:

var buffer = Buffer.alloc(65535);
var buffer = Buffer.from([
0x06, 0x27, 0xE2, 0xF1, 0xDD, 0x1D, 0x06, 0xCC, 0x72, 0x84, 0xD7, 0x79, 0x08, 0x00, 0x45, 0x00,
0x00, 0x54, 0xA3, 0x8A, 0x40, 0x00, 0x3E, 0x01, 0x24, 0xAE, 0x64, 0x60, 0x00, 0x01, 0x08, 0x08,
0x08, 0x08, 0x08, 0x00, 0x15, 0xAF, 0x07, 0x46, 0x00, 0x01, 0x39, 0x28, 0x0A, 0x5C, 0x00, 0x00,
0x00, 0x00, 0xD5, 0xB2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37
]);

var raw = require ("raw-socket");
var socket = raw.createSocket ({protocol: raw.Protocol.ICMP});
const decoders = require('cap').decoders;

var ret = decoders.Ethernet(buffer);
ret = decoders.IPV4(buffer, ret.offset);
offset = decoders.Ethernet(buffer).offset;
dst = ret.info.dstaddr;

var buffer = buffer.slice(ret.offset, nbytes);

var nbytes = 98;

socket.send (buffer, 0, buffer.length, dst, function (error, bytes) {
    if (error) console.log (error.toString ());
});

The buffer contains an ICMP packet with source IP 100.96.0.1, but tshark/wireshark shows the following:

393  16.488135 76.89.22.101 -> 8.8.8.8      ICMP 100 Echo (ping) request  id=0x0746, seq=1/256, ttl=64
394  16.496964      8.8.8.8 -> 76.89.22.101 ICMP 100 Echo (ping) reply    id=0x0746, seq=1/256, ttl=120 (request in 393)

Solution

  • You'll have to set the IP_HDRINCL flag to prevent the kernel from rewriting the IP header. That also means you need to include the IP header in your packet, thus use offset instead of ret.offset in your call to buffer.slice().

    Here's the update code:

    var buffer = Buffer.alloc(65535);
    var buffer = Buffer.from([
    0x06, 0x27, 0xE2, 0xF1, 0xDD, 0x1D, 0x06, 0xCC, 0x72, 0x84, 0xD7, 0x79, 0x08, 0x00, 0x45, 0x00,
    0x00, 0x54, 0xA3, 0x8A, 0x40, 0x00, 0x3E, 0x01, 0x24, 0xAE, 0x64, 0x60, 0x00, 0x01, 0x08, 0x08,
    0x08, 0x08, 0x08, 0x00, 0x15, 0xAF, 0x07, 0x46, 0x00, 0x01, 0x39, 0x28, 0x0A, 0x5C, 0x00, 0x00,
    0x00, 0x00, 0xD5, 0xB2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
    0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
    0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
    0x36, 0x37
    ]);
    
    var raw = require ("raw-socket");
    var socket = raw.createSocket ({protocol: raw.Protocol.ICMP});
    const decoders = require('cap').decoders;
    
    var ret = decoders.Ethernet(buffer);
    ret = decoders.IPV4(buffer, ret.offset);
    offset = decoders.Ethernet(buffer).offset;
    dst = ret.info.dstaddr;
    
    var buffer = buffer.slice(offset, nbytes);
    
    var nbytes = 98;
    
    socket.setOption(raw.SocketLevel.IPPROTO_IP, raw.SocketOption.IP_HDRINCL, new Buffer ([0x00, 0x00, 0x00, 0x01]), 4)
    socket.send (buffer, 0, buffer.length, dst, function (error, bytes) {
        if (error) console.log (error.toString ());
    });