Thu Aug 6 14:02:38 2009 UTC ()
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


(tnn)
diff -r1.27 -r1.28 pkgsrc/net/libfetch/files/ftp.c

cvs diff -r1.27 -r1.28 pkgsrc/net/libfetch/files/ftp.c (expand / switch to unified diff)

--- pkgsrc/net/libfetch/files/ftp.c 2009/02/22 19:11:48 1.27
+++ pkgsrc/net/libfetch/files/ftp.c 2009/08/06 14:02:38 1.28
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ftp.c,v 1.27 2009/02/22 19:11:48 joerg Exp $ */ 1/* $NetBSD: ftp.c,v 1.28 2009/08/06 14:02:38 tnn Exp $ */
2/*- 2/*-
3 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav 3 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
4 * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org> 4 * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer 11 * notice, this list of conditions and the following disclaimer
12 * in this position and unchanged. 12 * in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -610,29 +610,32 @@ ftp_setup(conn_t *cconn, conn_t *dconn,  @@ -610,29 +610,32 @@ ftp_setup(conn_t *cconn, conn_t *dconn,
610 f = fetchIO_unopen(io, ftp_readfn, ftp_writefn, ftp_closefn); 610 f = fetchIO_unopen(io, ftp_readfn, ftp_writefn, ftp_closefn);
611 if (f == NULL) 611 if (f == NULL)
612 free(io); 612 free(io);
613 return (f); 613 return (f);
614} 614}
615 615
616/* 616/*
617 * Transfer file 617 * Transfer file
618 */ 618 */
619static fetchIO * 619static fetchIO *
620ftp_transfer(conn_t *conn, const char *oper, const char *file, const char *op_arg, 620ftp_transfer(conn_t *conn, const char *oper, const char *file, const char *op_arg,
621 int mode, off_t offset, const char *flags) 621 int mode, off_t offset, const char *flags)
622{ 622{
623 struct sockaddr_storage sa; 623 union anonymous {
624 struct sockaddr_in6 *sin6; 624 struct sockaddr_storage ss;
625 struct sockaddr_in *sin4; 625 struct sockaddr sa;
 626 struct sockaddr_in6 sin6;
 627 struct sockaddr_in sin4;
 628 } u;
626 const char *bindaddr; 629 const char *bindaddr;
627 const char *filename; 630 const char *filename;
628 int filenamelen, type; 631 int filenamelen, type;
629 int low, pasv, verbose; 632 int low, pasv, verbose;
630 int e, sd = -1; 633 int e, sd = -1;
631 socklen_t l; 634 socklen_t l;
632 char *s; 635 char *s;
633 fetchIO *df; 636 fetchIO *df;
634 637
635 /* check flags */ 638 /* check flags */
636 low = CHECK_FLAG('l'); 639 low = CHECK_FLAG('l');
637 pasv = !CHECK_FLAG('a'); 640 pasv = !CHECK_FLAG('a');
638 verbose = CHECK_FLAG('v'); 641 verbose = CHECK_FLAG('v');
@@ -640,50 +643,50 @@ ftp_transfer(conn_t *conn, const char *o @@ -640,50 +643,50 @@ ftp_transfer(conn_t *conn, const char *o
640 /* passive mode */ 643 /* passive mode */
641 if (!pasv) 644 if (!pasv)
642 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL && 645 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL &&
643 strncasecmp(s, "no", 2) != 0); 646 strncasecmp(s, "no", 2) != 0);
644 647
645 /* isolate filename */ 648 /* isolate filename */
646 filename = ftp_filename(file, &filenamelen, &type, op_arg != NULL); 649 filename = ftp_filename(file, &filenamelen, &type, op_arg != NULL);
647 650
648 /* set transfer mode and data type */ 651 /* set transfer mode and data type */
649 if ((e = ftp_mode_type(conn, 0, type)) != FTP_OK) 652 if ((e = ftp_mode_type(conn, 0, type)) != FTP_OK)
650 goto ouch; 653 goto ouch;
651 654
652 /* find our own address, bind, and listen */ 655 /* find our own address, bind, and listen */
653 l = sizeof(sa); 656 l = sizeof(u.ss);
654 if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1) 657 if (getsockname(conn->sd, &u.sa, &l) == -1)
655 goto sysouch; 658 goto sysouch;
656 if (sa.ss_family == AF_INET6) 659 if (u.ss.ss_family == AF_INET6)
657 unmappedaddr((struct sockaddr_in6 *)&sa, &l); 660 unmappedaddr(&u.sin6, &l);
658 661
659retry_mode: 662retry_mode:
660 663
661 /* open data socket */ 664 /* open data socket */
662 if ((sd = socket(sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { 665 if ((sd = socket(u.ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
663 fetch_syserr(); 666 fetch_syserr();
664 return (NULL); 667 return (NULL);
665 } 668 }
666 669
667 if (pasv) { 670 if (pasv) {
668 unsigned char addr[64]; 671 unsigned char addr[64];
669 char *ln, *p; 672 char *ln, *p;
670 unsigned int i; 673 unsigned int i;
671 int port; 674 int port;
672 675
673 /* send PASV command */ 676 /* send PASV command */
674 if (verbose) 677 if (verbose)
675 fetch_info("setting passive mode"); 678 fetch_info("setting passive mode");
676 switch (sa.ss_family) { 679 switch (u.ss.ss_family) {
677 case AF_INET: 680 case AF_INET:
678 if ((e = ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE) 681 if ((e = ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
679 goto ouch; 682 goto ouch;
680 break; 683 break;
681 case AF_INET6: 684 case AF_INET6:
682 if ((e = ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) { 685 if ((e = ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
683 if (e == -1) 686 if (e == -1)
684 goto ouch; 687 goto ouch;
685 if ((e = ftp_cmd(conn, "LPSV")) != 688 if ((e = ftp_cmd(conn, "LPSV")) !=
686 FTP_LPASSIVE_MODE) 689 FTP_LPASSIVE_MODE)
687 goto ouch; 690 goto ouch;
688 } 691 }
689 break; 692 break;
@@ -736,151 +739,147 @@ retry_mode: @@ -736,151 +739,147 @@ retry_mode:
736 /* Close socket and retry with passive mode. */ 739 /* Close socket and retry with passive mode. */
737 pasv = 0; 740 pasv = 0;
738 close(sd); 741 close(sd);
739 sd = -1; 742 sd = -1;
740 goto retry_mode; 743 goto retry_mode;
741 } 744 }
742 745
743 /* seek to required offset */ 746 /* seek to required offset */
744 if (offset) 747 if (offset)
745 if (ftp_cmd(conn, "REST %lu", (unsigned long)offset) != FTP_FILE_OK) 748 if (ftp_cmd(conn, "REST %lu", (unsigned long)offset) != FTP_FILE_OK)
746 goto sysouch; 749 goto sysouch;
747 750
748 /* construct sockaddr for data socket */ 751 /* construct sockaddr for data socket */
749 l = sizeof(sa); 752 l = sizeof(u.ss);
750 if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1) 753 if (getpeername(conn->sd, &u.sa, &l) == -1)
751 goto sysouch; 754 goto sysouch;
752 if (sa.ss_family == AF_INET6) 755 if (u.ss.ss_family == AF_INET6)
753 unmappedaddr((struct sockaddr_in6 *)&sa, &l); 756 unmappedaddr(&u.sin6, &l);
754 switch (sa.ss_family) { 757 switch (u.ss.ss_family) {
755 case AF_INET6: 758 case AF_INET6:
756 sin6 = (struct sockaddr_in6 *)&sa; 
757 if (e == FTP_EPASSIVE_MODE) 759 if (e == FTP_EPASSIVE_MODE)
758 sin6->sin6_port = htons(port); 760 u.sin6.sin6_port = htons(port);
759 else { 761 else {
760 memcpy(&sin6->sin6_addr, addr + 2, 16); 762 memcpy(&u.sin6.sin6_addr, addr + 2, 16);
761 memcpy(&sin6->sin6_port, addr + 19, 2); 763 memcpy(&u.sin6.sin6_port, addr + 19, 2);
762 } 764 }
763 break; 765 break;
764 case AF_INET: 766 case AF_INET:
765 sin4 = (struct sockaddr_in *)&sa; 
766 if (e == FTP_EPASSIVE_MODE) 767 if (e == FTP_EPASSIVE_MODE)
767 sin4->sin_port = htons(port); 768 u.sin4.sin_port = htons(port);
768 else { 769 else {
769 memcpy(&sin4->sin_addr, addr, 4); 770 memcpy(&u.sin4.sin_addr, addr, 4);
770 memcpy(&sin4->sin_port, addr + 4, 2); 771 memcpy(&u.sin4.sin_port, addr + 4, 2);
771 } 772 }
772 break; 773 break;
773 default: 774 default:
774 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */ 775 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
775 break; 776 break;
776 } 777 }
777 778
778 /* connect to data port */ 779 /* connect to data port */
779 if (verbose) 780 if (verbose)
780 fetch_info("opening data connection"); 781 fetch_info("opening data connection");
781 bindaddr = getenv("FETCH_BIND_ADDRESS"); 782 bindaddr = getenv("FETCH_BIND_ADDRESS");
782 if (bindaddr != NULL && *bindaddr != '\0' && 783 if (bindaddr != NULL && *bindaddr != '\0' &&
783 fetch_bind(sd, sa.ss_family, bindaddr) != 0) 784 fetch_bind(sd, u.ss.ss_family, bindaddr) != 0)
784 goto sysouch; 785 goto sysouch;
785 if (connect(sd, (struct sockaddr *)&sa, l) == -1) 786 if (connect(sd, &u.sa, l) == -1)
786 goto sysouch; 787 goto sysouch;
787 788
788 /* make the server initiate the transfer */ 789 /* make the server initiate the transfer */
789 if (verbose) 790 if (verbose)
790 fetch_info("initiating transfer"); 791 fetch_info("initiating transfer");
791 if (op_arg) 792 if (op_arg)
792 e = ftp_cmd(conn, "%s%s%s", oper, *op_arg ? " " : "", op_arg); 793 e = ftp_cmd(conn, "%s%s%s", oper, *op_arg ? " " : "", op_arg);
793 else 794 else
794 e = ftp_cmd(conn, "%s %.*s", oper, 795 e = ftp_cmd(conn, "%s %.*s", oper,
795 filenamelen, filename); 796 filenamelen, filename);
796 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 797 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
797 goto ouch; 798 goto ouch;
798 799
799 } else { 800 } else {
800 uint32_t a; 801 uint32_t a;
801 uint16_t p; 802 uint16_t p;
802#if defined(IPV6_PORTRANGE) || defined(IP_PORTRANGE) 803#if defined(IPV6_PORTRANGE) || defined(IP_PORTRANGE)
803 int arg; 804 int arg;
804#endif 805#endif
805 int d; 806 int d;
806 char *ap; 807 char *ap;
807 char hname[INET6_ADDRSTRLEN]; 808 char hname[INET6_ADDRSTRLEN];
808 809
809 switch (sa.ss_family) { 810 switch (u.ss.ss_family) {
810 case AF_INET6: 811 case AF_INET6:
811 ((struct sockaddr_in6 *)&sa)->sin6_port = 0; 812 u.sin6.sin6_port = 0;
812#ifdef IPV6_PORTRANGE 813#ifdef IPV6_PORTRANGE
813 arg = low ? IPV6_PORTRANGE_DEFAULT : IPV6_PORTRANGE_HIGH; 814 arg = low ? IPV6_PORTRANGE_DEFAULT : IPV6_PORTRANGE_HIGH;
814 if (setsockopt(sd, IPPROTO_IPV6, IPV6_PORTRANGE, 815 if (setsockopt(sd, IPPROTO_IPV6, IPV6_PORTRANGE,
815 (char *)&arg, sizeof(arg)) == -1) 816 (char *)&arg, sizeof(arg)) == -1)
816 goto sysouch; 817 goto sysouch;
817#endif 818#endif
818 break; 819 break;
819 case AF_INET: 820 case AF_INET:
820 ((struct sockaddr_in *)&sa)->sin_port = 0; 821 u.sin4.sin_port = 0;
821#ifdef IP_PORTRANGE 822#ifdef IP_PORTRANGE
822 arg = low ? IP_PORTRANGE_DEFAULT : IP_PORTRANGE_HIGH; 823 arg = low ? IP_PORTRANGE_DEFAULT : IP_PORTRANGE_HIGH;
823 if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, 824 if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
824 (char *)&arg, sizeof(arg)) == -1) 825 (char *)&arg, sizeof(arg)) == -1)
825 goto sysouch; 826 goto sysouch;
826#endif 827#endif
827 break; 828 break;
828 } 829 }
829 if (verbose) 830 if (verbose)
830 fetch_info("binding data socket"); 831 fetch_info("binding data socket");
831 if (bind(sd, (struct sockaddr *)&sa, l) == -1) 832 if (bind(sd, &u.sa, l) == -1)
832 goto sysouch; 833 goto sysouch;
833 if (listen(sd, 1) == -1) 834 if (listen(sd, 1) == -1)
834 goto sysouch; 835 goto sysouch;
835 836
836 /* find what port we're on and tell the server */ 837 /* find what port we're on and tell the server */
837 if (getsockname(sd, (struct sockaddr *)&sa, &l) == -1) 838 if (getsockname(sd, &u.sa, &l) == -1)
838 goto sysouch; 839 goto sysouch;
839 switch (sa.ss_family) { 840 switch (u.ss.ss_family) {
840 case AF_INET: 841 case AF_INET:
841 sin4 = (struct sockaddr_in *)&sa; 842 a = ntohl(u.sin4.sin_addr.s_addr);
842 a = ntohl(sin4->sin_addr.s_addr); 843 p = ntohs(u.sin4.sin_port);
843 p = ntohs(sin4->sin_port); 
844 e = ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d", 844 e = ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
845 (a >> 24) & 0xff, (a >> 16) & 0xff, 845 (a >> 24) & 0xff, (a >> 16) & 0xff,
846 (a >> 8) & 0xff, a & 0xff, 846 (a >> 8) & 0xff, a & 0xff,
847 (p >> 8) & 0xff, p & 0xff); 847 (p >> 8) & 0xff, p & 0xff);
848 break; 848 break;
849 case AF_INET6: 849 case AF_INET6:
850#define UC(b) (((int)b)&0xff) 850#define UC(b) (((int)b)&0xff)
851 e = -1; 851 e = -1;
852 sin6 = (struct sockaddr_in6 *)&sa; 852 u.sin6.sin6_scope_id = 0;
853 sin6->sin6_scope_id = 0; 853 if (getnameinfo(&u.sa, l,
854 if (getnameinfo((struct sockaddr *)&sa, l, 
855 hname, sizeof(hname), 854 hname, sizeof(hname),
856 NULL, 0, NI_NUMERICHOST) == 0) { 855 NULL, 0, NI_NUMERICHOST) == 0) {
857 e = ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname, 856 e = ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
858 htons(sin6->sin6_port)); 857 htons(u.sin6.sin6_port));
859 if (e == -1) 858 if (e == -1)
860 goto ouch; 859 goto ouch;
861 } 860 }
862 if (e != FTP_OK) { 861 if (e != FTP_OK) {
863 ap = (char *)&sin6->sin6_addr; 862 ap = (char *)&u.sin6.sin6_addr;
864 e = ftp_cmd(conn, 863 e = ftp_cmd(conn,
865 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 864 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
866 6, 16, 865 6, 16,
867 UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]), 866 UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
868 UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]), 867 UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]),
869 UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]), 868 UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]),
870 UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]), 869 UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]),
871 2, 870 2,
872 (ntohs(sin6->sin6_port) >> 8) & 0xff, 871 (ntohs(u.sin6.sin6_port) >> 8) & 0xff,
873 ntohs(sin6->sin6_port) & 0xff); 872 ntohs(u.sin6.sin6_port) & 0xff);
874 } 873 }
875 break; 874 break;
876 default: 875 default:
877 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */ 876 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
878 goto ouch; 877 goto ouch;
879 } 878 }
880 if (e != FTP_OK) 879 if (e != FTP_OK)
881 goto ouch; 880 goto ouch;
882 881
883 /* seek to required offset */ 882 /* seek to required offset */
884 if (offset) 883 if (offset)
885 if (ftp_cmd(conn, "REST %llu", (unsigned long long)offset) != FTP_FILE_OK) 884 if (ftp_cmd(conn, "REST %llu", (unsigned long long)offset) != FTP_FILE_OK)
886 goto sysouch; 885 goto sysouch;