diff options
author | tnn <tnn@pkgsrc.org> | 2009-08-06 14:02:38 +0000 |
---|---|---|
committer | tnn <tnn@pkgsrc.org> | 2009-08-06 14:02:38 +0000 |
commit | 758e4ca38cc97008ef8c75dc03a1da9ae6977c5a (patch) | |
tree | 699732a42aa717db1a255558085bfcd4578bd1c4 /net/libfetch | |
parent | 56a85db5bd14a36a72a5ad897c66ad18d4bd320d (diff) | |
download | pkgsrc-758e4ca38cc97008ef8c75dc03a1da9ae6977c5a.tar.gz |
Fix strict aliasing issue which GCC 4.4 complained about.
While we know that "struct sockaddr_storage" has been engineered to alias
to all the sockaddr structs, the compiler does not know about this.
Thus, code like this may be unsafe to use:
struct sockaddr_storage ss;
struct sockaddr_in *sin = &ss;
sin->sin_port = 0; /* dereferencing here breaks ISO C aliasing rules */
A workaround is to wrap the struct in a union, e.g:
union anonymous {
struct sockaddr_storage ss;
struct sockaddr_in sin;
} u;
u.sin.sin_port = 0;
--
Approved by: joerg
Diffstat (limited to 'net/libfetch')
-rw-r--r-- | net/libfetch/files/ftp.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/net/libfetch/files/ftp.c b/net/libfetch/files/ftp.c index 0ad6aa69bfa..9c33d779ec0 100644 --- a/net/libfetch/files/ftp.c +++ b/net/libfetch/files/ftp.c @@ -1,4 +1,4 @@ -/* $NetBSD: ftp.c,v 1.27 2009/02/22 19:11:48 joerg Exp $ */ +/* $NetBSD: ftp.c,v 1.28 2009/08/06 14:02:38 tnn Exp $ */ /*- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org> @@ -620,9 +620,12 @@ static fetchIO * ftp_transfer(conn_t *conn, const char *oper, const char *file, const char *op_arg, int mode, off_t offset, const char *flags) { - struct sockaddr_storage sa; - struct sockaddr_in6 *sin6; - struct sockaddr_in *sin4; + union anonymous { + struct sockaddr_storage ss; + struct sockaddr sa; + struct sockaddr_in6 sin6; + struct sockaddr_in sin4; + } u; const char *bindaddr; const char *filename; int filenamelen, type; @@ -650,16 +653,16 @@ ftp_transfer(conn_t *conn, const char *oper, const char *file, const char *op_ar goto ouch; /* find our own address, bind, and listen */ - l = sizeof(sa); - if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1) + l = sizeof(u.ss); + if (getsockname(conn->sd, &u.sa, &l) == -1) goto sysouch; - if (sa.ss_family == AF_INET6) - unmappedaddr((struct sockaddr_in6 *)&sa, &l); + if (u.ss.ss_family == AF_INET6) + unmappedaddr(&u.sin6, &l); retry_mode: /* open data socket */ - if ((sd = socket(sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { + if ((sd = socket(u.ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { fetch_syserr(); return (NULL); } @@ -673,7 +676,7 @@ retry_mode: /* send PASV command */ if (verbose) fetch_info("setting passive mode"); - switch (sa.ss_family) { + switch (u.ss.ss_family) { case AF_INET: if ((e = ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE) goto ouch; @@ -746,28 +749,26 @@ retry_mode: goto sysouch; /* construct sockaddr for data socket */ - l = sizeof(sa); - if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1) + l = sizeof(u.ss); + if (getpeername(conn->sd, &u.sa, &l) == -1) goto sysouch; - if (sa.ss_family == AF_INET6) - unmappedaddr((struct sockaddr_in6 *)&sa, &l); - switch (sa.ss_family) { + if (u.ss.ss_family == AF_INET6) + unmappedaddr(&u.sin6, &l); + switch (u.ss.ss_family) { case AF_INET6: - sin6 = (struct sockaddr_in6 *)&sa; if (e == FTP_EPASSIVE_MODE) - sin6->sin6_port = htons(port); + u.sin6.sin6_port = htons(port); else { - memcpy(&sin6->sin6_addr, addr + 2, 16); - memcpy(&sin6->sin6_port, addr + 19, 2); + memcpy(&u.sin6.sin6_addr, addr + 2, 16); + memcpy(&u.sin6.sin6_port, addr + 19, 2); } break; case AF_INET: - sin4 = (struct sockaddr_in *)&sa; if (e == FTP_EPASSIVE_MODE) - sin4->sin_port = htons(port); + u.sin4.sin_port = htons(port); else { - memcpy(&sin4->sin_addr, addr, 4); - memcpy(&sin4->sin_port, addr + 4, 2); + memcpy(&u.sin4.sin_addr, addr, 4); + memcpy(&u.sin4.sin_port, addr + 4, 2); } break; default: @@ -780,9 +781,9 @@ retry_mode: fetch_info("opening data connection"); bindaddr = getenv("FETCH_BIND_ADDRESS"); if (bindaddr != NULL && *bindaddr != '\0' && - fetch_bind(sd, sa.ss_family, bindaddr) != 0) + fetch_bind(sd, u.ss.ss_family, bindaddr) != 0) goto sysouch; - if (connect(sd, (struct sockaddr *)&sa, l) == -1) + if (connect(sd, &u.sa, l) == -1) goto sysouch; /* make the server initiate the transfer */ @@ -806,9 +807,9 @@ retry_mode: char *ap; char hname[INET6_ADDRSTRLEN]; - switch (sa.ss_family) { + switch (u.ss.ss_family) { case AF_INET6: - ((struct sockaddr_in6 *)&sa)->sin6_port = 0; + u.sin6.sin6_port = 0; #ifdef IPV6_PORTRANGE arg = low ? IPV6_PORTRANGE_DEFAULT : IPV6_PORTRANGE_HIGH; if (setsockopt(sd, IPPROTO_IPV6, IPV6_PORTRANGE, @@ -817,7 +818,7 @@ retry_mode: #endif break; case AF_INET: - ((struct sockaddr_in *)&sa)->sin_port = 0; + u.sin4.sin_port = 0; #ifdef IP_PORTRANGE arg = low ? IP_PORTRANGE_DEFAULT : IP_PORTRANGE_HIGH; if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, @@ -828,19 +829,18 @@ retry_mode: } if (verbose) fetch_info("binding data socket"); - if (bind(sd, (struct sockaddr *)&sa, l) == -1) + if (bind(sd, &u.sa, l) == -1) goto sysouch; if (listen(sd, 1) == -1) goto sysouch; /* find what port we're on and tell the server */ - if (getsockname(sd, (struct sockaddr *)&sa, &l) == -1) + if (getsockname(sd, &u.sa, &l) == -1) goto sysouch; - switch (sa.ss_family) { + switch (u.ss.ss_family) { case AF_INET: - sin4 = (struct sockaddr_in *)&sa; - a = ntohl(sin4->sin_addr.s_addr); - p = ntohs(sin4->sin_port); + a = ntohl(u.sin4.sin_addr.s_addr); + p = ntohs(u.sin4.sin_port); e = ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d", (a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff, @@ -849,18 +849,17 @@ retry_mode: case AF_INET6: #define UC(b) (((int)b)&0xff) e = -1; - sin6 = (struct sockaddr_in6 *)&sa; - sin6->sin6_scope_id = 0; - if (getnameinfo((struct sockaddr *)&sa, l, + u.sin6.sin6_scope_id = 0; + if (getnameinfo(&u.sa, l, hname, sizeof(hname), NULL, 0, NI_NUMERICHOST) == 0) { e = ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname, - htons(sin6->sin6_port)); + htons(u.sin6.sin6_port)); if (e == -1) goto ouch; } if (e != FTP_OK) { - ap = (char *)&sin6->sin6_addr; + ap = (char *)&u.sin6.sin6_addr; e = ftp_cmd(conn, "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 6, 16, @@ -869,8 +868,8 @@ retry_mode: UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]), UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]), 2, - (ntohs(sin6->sin6_port) >> 8) & 0xff, - ntohs(sin6->sin6_port) & 0xff); + (ntohs(u.sin6.sin6_port) >> 8) & 0xff, + ntohs(u.sin6.sin6_port) & 0xff); } break; default: |