自己动手学TCP/IP–tftp协议

系统 1798 0

TFTP(Trivial File Transfer Protocol,简单 文件传输协议

1.tftp的服务端口号是69

2.tftp是基于udp协议的

3.tftp是明文传输的,是一种比较轻量型的协议,一般用于bootloader加载内核

TFTP工作流程

服务端开启tftp服务,tftp是一种stand_alone服务,不是常驻内存的,是在有需要的时候才去调用的。首先,客户端发送一个读(RRQ:2个字节)或者写(WRQ:2个字节)的请求,数据包的目标端口是69。对于读或者写的报文格式如下:

RRQ/WRQ(2个字节)+文件名(N字节)+0(1字节)+模式(N字节)+0(1字节)

目前模式字段主要有2种:netascii,这是8位的ASCII码形式;另一种是octet,这是8位源数据类型。对于netascii是把回车和换行(CR/LF)解释成两个字节的。可以查看 http://www.firefoxbug.net/?p=1041

tftp-server接收到数据包:如果是发现是读(RRQ),就重新随机分配一个端口,直接发送数据(DATA:2个字节)+块编号(2个字节),然后是0~512字节数据包。客户端接收到数据包,发给服务端(ACK:2个字节)+块编号(2个字节)。如果是普通的数据包,那么数据段的大小一定是512字节,如果是最后一个数据包,肯定是小于512字节的。tftp就是通过发现了一个数据段小于512字节的数据包来声明结束文件的传输了。那么一个要传输的文件刚还是512字节的整数倍怎么办呢?tftp会在最后传输一个数据段大小是0包。

tftp-server接收到数据包:如果发现是写(WRQ),服务端就发回(ACK:2个字节)+(块编号0:2个字节)的包,接着客户端就发送(DATA:2个字节)+(块编号1:2个字节)+数据段给服务端,服务端发回(ACK:2个字节)+(块编号1:2个字节)。。。依次发送。

错误信息是系统自定义的,格式主要是error(2个字节)+错误码(2个字节)+错误信息(N个字节)

下面是tftp数据包的格式图


下面是C语言解析tftp包的一小段代码:

    struct  tftphdr {
        short   th_opcode;                      /* packet type */
        union {
                unsigned short  tu_block;       /* block # */
                short   tu_code;                /* error code */
                char    tu_stuff[1];            /* request packet stuff */
        } __attribute__ ((__packed__)) th_u;
        char    th_data[1];                     /* data or error string */
} __attribute__ ((__packed__));

// 解析udp包,packet_buffer是用rawsocket抓出来的以太网包,
void ParseUDPPacket(unsigned char *packet_buffer)
{
    struct ethhdr *eth_header;//以太网头
    struct iphdr *ip_header; //ip头
    struct udphdr *udp_header; //tcp头
    eth_header = (struct ethhdr*)packet_buffer;
    ip_header = (struct iphdr*)(packet_buffer + sizeof(struct ethhdr));
    udp_header = (struct udphdr*)(packet_buffer + sizeof(struct ethhdr) + ip_header->ihl*4);
    unsigned char *data = NULL;
    data = (packet_buffer + sizeof(struct ethhdr) + ip_header->ihl*4 + 8);//8代表UDP包头
    struct tftphdr *tp = (struct tftphdr *)data;    //  /usr/include/arpa/tftp.h
    tftp_print(data,ntohs(udp_header->len)-8);  //ntohs(udp_header->len)-8表示udp数据包长度
}

/*
* Print trivial file transfer program requests
*/
void tftp_print(register const u_char *bp, u_int length)
{
    register const struct tftphdr *tp;
    register const u_char *p;
    register int opcode,i;
    static char tstr[] = " [|tftp]";
    char buffer[520] = {'\0'};
    tp = (const struct tftphdr *)bp;

    // printf(" %d", length);
    // printf("length of tftp_data = %d\n",length);

    /* Print tftp request type */

    opcode = EXTRACT_16BITS(&tp->th_opcode);
    printf(" %s",tok2str(op2str, "tftp-#%d", opcode));
    /* Bail if bogus opcode */

    switch (opcode) {

        case RRQ:
        break;

        case WRQ:
        break;

        case ACK:
        break;

        case DATA:
        break;

        case ERROR:
        break;

        default:
        /* We shouldn't get here */
        printf("(unknown #%d)", opcode);
        break;
    }
    return;
}
  

详细的可以查看tcpdump的源码。

自己动手学TCP/IP–tftp协议


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论