何时在C中使用ntohs和ntohl? [英] When to use ntohs and ntohl in C?

查看:136
本文介绍了何时在C中使用ntohs和ntohl?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对何时使用ntohs和ntohl感到非常困惑.我知道您将ntohs用于uint16_t和ntohl uint32_t.但是对于那些无符号int的那些或指定了特定位数的那些呢(例如u_int16_t doff:4;).

I'm very confused in when to use ntohs and ntohl. I know when you use ntohs for uint16_t and ntohl uint32_t. But what about those with unsigned int or those where a specific amount of bits is specified (e.g. u_int16_t doff:4;).

这是我的工作代码,可以用来解决此问题:

Here is my working code to demostrate the issue:

// Utility/Debugging method for dumping raw packet data
void dump(const unsigned char *data, int length) {
    unsigned int i;
    static unsigned long pcount = 0;

    // Decode Packet Header
    struct ether_header *eth_header = (struct ether_header *) data;

    printf("\n\n === PACKET %ld HEADER ===\n", pcount);

    printf("\nSource MAC: ");
    for (i = 0; i < 6; ++i) {
        printf("%02x", eth_header->ether_shost[i]);
        if (i < 5) {
            printf(":");
        }
    }

    printf("\nDestination MAC: ");
    unsigned short ethernet_type = ntohs(eth_header->ether_type);
    printf("\nType: %hu\n", ethernet_type); //Why not nthos?

    if (ethernet_type == ETHERTYPE_IP) { //IP Header
        printf("\n == IP HEADER ==\n");
        struct ip *ip_hdr = (struct ip*) (data + sizeof(struct ether_header));
        unsigned int size_ip = ip_hdr->ip_hl * 4; //why no nthos or nthol
        printf("\nip_hdr->ip_hl: %u", ip_hdr->ip_hl); //why no nthos or nthol
        printf("\nIP Version: %u", ip_hdr->ip_v); //why no nthos or nthol
        printf("\nHeader Length: %u", ip_hdr->ip_hl); //why no nthos or nthol
        printf("\nTotal Length: %hu", ntohs(ip_hdr->ip_len)); //?is this right?

        // TCP Header
        printf("\n== TCP HEADER ==\n");
        struct tcphdr *tcp_hdr = (struct tcphdr*) (data + sizeof(struct ether_header) + size_ip);
        unsigned int size_tcp = tcp_hdr->doff * 4; //why no nthos or nthol
        printf("\n Source Port: %" PRIu16, ntohs(tcp_hdr->th_sport)); 
        printf("\n Destination Port: %" PRIu16, ntohs(tcp_hdr->th_dport));
        printf("\n fin: %" PRIu16, tcp_hdr->fin ); //As this is 1 bit, both nthos or nthol will work
        printf("\n urg: %" PRIu16, tcp_hdr->urg ); //As this is 1 bit, both nthos or nthol will work
        printf("\n ack_seq: %" PRIu32, ntohl(tcp_hdr->ack_seq));

        u_int16_t sourcePort = ntohs(tcp_hdr->th_sport);
        u_int16_t destinationPort = ntohs(tcp_hdr->th_sport);

        if (sourcePort == 80 || destinationPort == 80){
            printf("\n\nPORT 80!!!\n");

            //Transport payload!
            printf("\n\  === TCP PAYLOAD DATA == \n");

            // Decode Packet Data (Skipping over the header)
            unsigned int headers_size = ETH_HLEN + size_ip + size_tcp;
            unsigned int data_bytes = length - headers_size;
            const unsigned char *payload = data + headers_size;

            const static int output_sz = 500; // Output this many bytes at a time
            while (data_bytes > 0) {
                int output_bytes = data_bytes < output_sz ? data_bytes : output_sz;
                // Print data in raw hexadecimal form
                printf("| ");
                // Print data in ascii form
                for (i = 0; i < output_bytes; ++i) {
                    char byte = payload[i];
                    if ( (byte > 31 && byte < 127) || byte == '\n') {
                        // Byte is in printable ascii range
                        printf("%c", byte);  //why no nthos or nthol
                    } else {
                        printf(".");
                    }
                }
                payload += output_bytes;
                data_bytes -= output_bytes;
            }
        }

    }

    pcount++;
}

您可以看到有些时候我使用ntohs/ntohl,有些时候我都不使用.我不知道何时使用.

As you can see there are times I use ntohs/ntohl and there are times I use neither. I don't understand when to use which.

推荐答案

但是那些unsigned int的人呢

But what about those with unsigned int

如前所述,原则上C不保证unsigned int的大小;某些平台上的intunsigned int是16位的,例如PDP-11,以及带有某些编译器的Motorola 68k处理器(其他编译器将它们编译为32位),并且对于一些16位微处理器.

In principle, as noted, C makes no guarantee of the size of unsigned int; there were platforms on which int and unsigned int were 16-bit, such as the PDP-11, and the Motorola 68k processors with some compilers (other compilers made them 32-bit), and that may still be the case for some 16-bit microprocessors.

因此,如果要通过网络发送数据,则最好使用<stdint.h>中定义的类型.

So, if you're sending data over the wire, it's best to use the types defined in <stdint.h> if that's available.

实际上,您所使用的计算机几乎肯定会具有32位的unsigned int

In practice, the machines you're using will almost certainly have a 32-bit unsigned int, although some Cray machines have 64-bit int and even short! But it's still best to use the types defined in <stdint.h>.

或指定了特定位数的位(例如u_int16_t doff:4;).

or those where a specific amount of bits is specified (e.g. u_int16_t doff:4;).

如果值短于字节(例如4位字段),则字节顺序无关紧要.

If a value is shorter than a byte, as would be the case for a 4-bit field, byte order is irrelevant.

但是,请注意, 在1、2或4个字节序列内的位字段的顺序也是 ,C并未指定,因此您不应在通过网络发送的数据中使用位字段. (是的,某些UN * X恰好在IPv4和TCP标头的结构中使用它们,但只有在供应商为其支持的体系结构所使用的编译器使用相同顺序放置所有位域并且第三方使用的情况下,这些方法才有效像GCC这样的编译器也做同样的事情.)

However, note that the order of bit fields within a sequence of 1, 2, or 4 bytes is also not specified by C, so you shouldn't use bit fields in data sent over the wire. (Yes, some UN*Xes happen to use them in the structures for IPv4 and TCP headers, but that only works if the compilers the vendor uses for the architectures they support all put bit-fields in the same order, and if third-party compilers such as GCC do the same thing.)

因此,处理IPv4标头的正确方法是执行诸如

So the proper way of handling the IPv4 header is to do something such as

struct ip {
        uint8_t         ip_vhl;         /* header length, version */
#define IP_V(ip)        (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip)       ((ip)->ip_vhl & 0x0f)
        uint8_t         ip_tos;         /* type of service */
        uint16_t        ip_len;         /* total length */
        uint16_t        ip_id;          /* identification */
        uint16_t        ip_off;         /* fragment offset field */
#define IP_DF 0x4000                    /* dont fragment flag */
#define IP_MF 0x2000                    /* more fragments flag */
#define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
        uint8_t         ip_ttl;         /* time to live */
        uint8_t         ip_p;           /* protocol */
        uint16_t        ip_sum;         /* checksum */
        struct  in_addr ip_src,ip_dst;  /* source and dest address */
};

使用 that 结构声明指向IP标头的ip_hdr指针,然后:

use that structure to declare your ip_hdr pointer to the IP header, and:

  • 要提取版本,请使用IP_V(ip_hdr);
  • 要提取标头长度,请使用IP_HL(ip_hdr).
  • to extract the version, use IP_V(ip_hdr);
  • to extract the header length, use IP_HL(ip_hdr).

如果供应商的ip.h标头使用位域,请不要使用供应商的ip.h标头;使用您自己的标题.实际上,即使您的供应商的ip.h标头使用位域,也不要使用您的供应商的ip.h标头.使用您自己的标题.毕竟,IP头的定义似乎并不依赖于操作系统.

If your vendor's ip.h header uses bitfields, don't use your vendor's ip.h header; use your own header. In fact, even if your vendor's ip.h header doesn't use bitfields, don't use your vendor's ip.h header; use your own header. It's not as if the definition of the IP header is OS-dependent, after all....

(这是tcpdump现在几个发行版中所做的;以上摘录自其ip.h.)

(That's what tcpdump has done for several releases now; the above is taken from its ip.h.)

这篇关于何时在C中使用ntohs和ntohl?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆