安全地从struct sockaddr转换为struct sockaddr_storage

时间:2016-06-07 15:47:33

标签: c pointers tcp network-programming ipv6

我有一个接受" struct sockaddr *"作为参数(让我们调用此input_address),然后我需要对该地址进行操作,该地址可能是sockaddr_in或sockaddr_in6,因为我同时支持IPv4和IPv6。

我收到了一些内存损坏并尝试将其追踪到它的来源,并且在此过程中发现了一些看起来很可疑的代码,所以我想验证这是否是正确的方法做事。

struct sockaddr_storage *input_address_storage = (struct sockaddr_storage *) input_address;
struct sockaddr_storage result = [UtilityClass performSomeOperation: *input_address_storage];

起初我认为第一行中的强制转换是安全的,但是在第二行中我需要取消引用该指针,这似乎可能是错误的。我担心的原因是它最终可能会复制超出原始结构的内存(因为sockaddr_in比sockaddr_in6短)。我不确定这是否会导致内存损坏(我的猜测是否定的),但是这段代码让我感觉很糟糕。

我无法改变我的函数采用" struct sockaddr *"这样的事实,所以似乎很难解决这类代码,但我想避免从我不应该的记忆位置复制。

如果有人能够验证我所做的事情是否错误,以及解决这个问题的最佳方法,我会很感激。

编辑:由于某种原因,管理员已经为C#更改了我的C标记。我给出的代码主要是C,来自目标C的一个函数调用并不重要。那个电话可能是C。

1 个答案:

答案 0 :(得分:0)

您的方法存在的问题是您要将现有的struct sockaddr*转换为struct sockaddr_storage*。想象一下,如果原版是一个``struct sockaddr_in . Since sizeof(struct sockaddr_in)< sizeof(struct sockaddr_storage)`,内存清理程序抱怨未绑定的内存引用。

struct sockaddr_storage基本上是container,可以包含struct sockaddr_instruct sockaddr_in6

因此,当您想要传递struct sockaddr*对象但希望为sockaddr_insockaddr_in6分配足够的内存时,它非常有用。

一个很好的例子是recvfrom(3)电话:

ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
                 int flags, struct sockaddr *restrict address,
                 socklen_t *restrict address_len);

由于address需要struct sockaddr*个对象,我们首先构建一个struct sockaddr_storage,并将其传递给:

struct sockaddr_storage address;
socklen_t address_length = sizeof(struct sockaddr_storage);
ssize_t ret = recvfrom(fd, buffer, buffer_length, 0, (struct sockaddr*)&address, &address_length);

if (address.ss_family == AF_INET) {
  DoIpv4Work((struct sockaddr_in*)&address, ...);
} else if (address.ss_family == AF_INET6) {
  DoIpv6Work((struct sockaddr_in6*)&address, ...);
}

您和我的方法的不同之处在于我分配了一个struct sockaddr_storage,然后将其用作struct sockaddr,但您执行 REVERSE ,并使用{{1然后将其用作struct sockaddr