zoukankan      html  css  js  c++  java
  • DNS协议 TCP转发 测试驱动开发

    研究A Query请求

    首先,启动一个UDP监听服务,打印请求:

    import * as udp from 'dgram';
    
    interface ServerConfig {
        host: string;
        port: number;
    }
    
    function main(config: ServerConfig) {
        var server = udp.createSocket('udp4');
        server.bind({
            port: config.port,
            address: config.host,
        }, () => {
            task(server);
        });
        server.on('error', (err) => {
            console.error(err);
        });
    }
    
    main({
        host: 'localhost',
        port: 53,
    });
    
    function task(server: udp.Socket) {
        server.on('message', (msg) => {
            console.log('conn', msg);
        });
    }
    

    使用dig发送一个请求

    $ dig @localhost a
    conn <Buffer 56 64 01 20 00 01 00 00 00 00 00 01 00 00 02 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 40 23 44 f8 9a 88 91 99>
    
    $ dig @localhost b
    conn <Buffer 6d df 01 20 00 01 00 00 00 00 00 01 01 62 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 72 b4 05 cf c0 9b 95 6b>
    

    长度居然不相同,换个域名:

    $ dig @localhost google.com
    2b c3 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 3b 32 50 88 3e bd 80 ... 1 more byte>
    bf 39 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 2c 3b d4 6c f2 d0 8f ... 1 more byte>
    16 35 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 b7 12 05 94 3e 14 f2 ... 1 more byte>
    4f 58 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 8a f3 ed fb c8 66 e5 ... 1 more byte>
                                           g  o  o  g  l  e  ?  c  o  m
    

    研究转发

    import * as udp from 'dgram';
    
    interface ServerConfig {
        host: string;
        port: number;
    }
    
    function main(config: ServerConfig) {
        var server = udp.createSocket('udp4');
        server.bind({
            port: config.port,
            address: config.host,
        }, () => {
            task(server);
        });
        server.on('error', (err) => {
            console.error(err);
        });
    }
    
    main({
        host: 'localhost',
        port: 53,
    });
    
    function task(server: udp.Socket) {
        server.on('message', (msg, rinfo) => {
            console.log(rinfo);
            printMsg(msg, 'conn');
    
            // forward to 1.1.1.1
            var nds = udp.createSocket('udp4');
            nds.send(msg, 53, '1.1.1.1');
            nds.on('message', (msg) => {
                printMsg(msg, 'forward');
                server.send(msg, rinfo.port, rinfo.address);
            });
        });
    }
    
    function printMsg(msg: Buffer, hint: string) {
        console.log(`===============${hint}:==================`);
        console.log(msg.buffer);
    
        var le = msg.byteLength;
        var str = '';
        for (let i = 0; i < le; i++) {
            str += String.fromCharCode(msg[i]);
        }
        console.log(`try read:`, str);
    }
    

    使用dig @localhost google.com查看:

    { address: '127.0.0.1', family: 'IPv4', port: 56797, size: 51 }
    ===============conn:==================
    ArrayBuffer {
      [Uint8Contents]: <2c 3c 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 37 30 eb c9 e3 37 83 9b>,
      byteLength: 51
    }
    try read: ,< googlecom)
    
    70ëÉã7
    ===============forward:==================             <== 运营商先返回一个污染的数据包
    ArrayBuffer {
      [Uint8Contents]: <2c 3c 85 80 00 01 00 01 00 00 00 00 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 00 3c
                        00 04
                        2e 52 ae 45>,
      byteLength: 54
    }
    try read: ,<
    googlecomgooglecom<.R®E
    ===============forward:==================             <== 真实的数据包到达,数据还被篡改了
    ArrayBuffer {
      [Uint8Contents]: <2c 3c 81 80 00 01 00 01 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 01 00 01 00 00 00 87 00 04 ac d9 04 ae 00 00 29 04 d0
                        00 00
                        00 00 00 00>,
      byteLength: 55
    }
    try read: ,<googlecomÀ
                          ¬Ù®)Ð
    

    转发效果:

    $ dig @localhost google.com
    
    ; <<>> DiG 9.16.1-Ubuntu <<>> @localhost google.com
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11324
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;google.com.			IN	A
    
    ;; ANSWER SECTION:
    google.com.		60	IN	A	46.82.174.69       <= 就是2e 52 ae 45
    
    ;; Query time: 23 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: 六 1月 30 16:17:30 CST 2021
    ;; MSG SIZE  rcvd: 54
    

    可否直接将udp请求使用tcp转发

    tcp与udp的A query请求:

    tcp
    00 33 21 44 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 74 95 9e ba f5 2f 7e fe
    00 33 24 ea 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 2e 00 32 09 ce 45 2b 1b
    
    udp
    90 97 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 f7 af 83 bf 5a 55 b8 9a
    2e 3c 01 20 00 01 00 00 00 00 00 01 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0c 00 0a 00 08 97 97 e4 eb 82 52 f4 45
    

    注意观察, tcp前面多了两个字节:0x00 0x33!仅此而已!
    let's go!

    function task(server: udp.Socket, config: ServerConfig) {
        server.on('message', (msg, rinfo) => {
            console.log(rinfo);
            printMsg(msg, 'conn');
    
            // forward to DNS server
            var dnsServer = config.server || '1.1.1.1';
            var tcp = net.createConnection({ host: dnsServer, port: 53 }, () => {
                console.log('server connected...');
    
                // add "0x00 0x33"
                var tcpQuery = Buffer.alloc(2 + msg.length);
                tcpQuery[0] = 0x00;
                tcpQuery[1] = 0x33;
                for (var i = 2; i < tcpQuery.length; i++) {
                    tcpQuery[i] = msg[i - 2];
                }
                printMsg(tcpQuery, 'forward');
    
                tcp.write(tcpQuery);
                tcp.once('data', (resp) => {
                    // delete "0x00 0x33"
                    var tcpResp = Buffer.alloc(msg.length);
                    for (var i = 0; i < tcpResp.length; i++) {
                        tcpResp[i] = resp[i + 2];
                    }
                    printMsg(tcpResp, 'resp');
                    server.send(tcpResp, rinfo.port, rinfo.address);
                });
            });
        });
    }
    

    修改/etc/resolv.conf

    备份软连接:

    $ ls -lih /etc/resolv.conf
    1048783 lrwxrwxrwx 1 root root 39 1月  22 20:39 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
    
    $ ls /run/systemd/resolve/stub-resolv.conf
    /run/systemd/resolve/stub-resolv.conf
    
    $ echo 'nameserver 127.0.0.1' > /etc/resolv.conf
    

    更正

    使用过程中发现只有固定的测试dig google.com可以被正确处理,研究发现TCP并不是固定前两个字节,0x33等于51,是字节长度!

    DNS的TCP协议与UDP协议相同,只是有一个区别-通过TCP发送的消息以网络字节顺序以16位整数作为前缀,以指定消息字节的长度。UDP不需要这样做,因为消息长度由数据报的大小决定。

    See: https://stackoverflow.com/questions/41512591/dns-query-over-tcp

  • 相关阅读:
    Manjaro 安装 VMware Pro 15
    RAID-0-10 搭建和使用
    列表的切换按钮,是什么实现的?
    动态表单的设计
    如何修改自定义表单的名字,不适用diyname,直接使用id
    php关于批量替换的测试
    fastadmin删除控制器,删除菜单,提示not found
    fastadmin自定义表单,如何根据字段信息,创建表,而且,可以随时修改字段的顺序
    fastadmin如何获取新增后的id,这个可以使用模型的钩子函数。
    fastadmin如何在弹窗内跳转?以及如何在非弹窗页面,做tab选项卡
  • 原文地址:https://www.cnblogs.com/develon/p/14347708.html
Copyright © 2011-2022 走看看