77fd54a0b11730ee1d001c2c655018caa8530741
[debian/amanda] / common-src / sockaddr-util.c
1 /*
2  * Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  *
20  * Author: Dustin J. Mitchell <dustin@zmanda.com>
21  */
22 /*
23  * Utility routines for handling sockaddrs
24  */
25
26 #include "sockaddr-util.h"
27
28 void
29 dump_sockaddr(
30     struct sockaddr_storage *sa)
31 {
32 #ifdef WORKING_IPV6
33     char ipstr[INET6_ADDRSTRLEN];
34 #else
35     char ipstr[INET_ADDRSTRLEN];
36 #endif
37     int port;
38
39     port = SS_GET_PORT(sa);
40 #ifdef WORKING_IPV6
41     if (sa->ss_family == (sa_family_t)AF_INET6) {
42         inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
43                   ipstr, sizeof(ipstr));
44         dbprintf("(sockaddr_in6 *)%p = { %d, %d, %s }\n",
45                  sa,
46                  ((struct sockaddr_in6 *)sa)->sin6_family,
47                  port,
48                  ipstr);
49     } else
50 #endif
51     {
52         inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
53                   sizeof(ipstr));
54         dbprintf("(sockaddr_in *)%p = { %d, %d, %s }\n",
55                  sa,
56                  ((struct sockaddr_in *)sa)->sin_family,
57                  port,
58                  ipstr);
59     }
60 }
61
62
63 #ifdef WORKING_IPV6
64 static char mystr_sockaddr[INET6_ADDRSTRLEN + 20];
65 #else
66 static char mystr_sockaddr[INET_ADDRSTRLEN + 20];
67 #endif
68
69 char *
70 str_sockaddr(
71     struct sockaddr_storage *sa)
72 {
73 #ifdef WORKING_IPV6
74     char ipstr[INET6_ADDRSTRLEN];
75 #else
76     char ipstr[INET_ADDRSTRLEN];
77 #endif
78     int port;
79
80     port = SS_GET_PORT(sa);
81 #ifdef WORKING_IPV6
82     if ( sa->ss_family == (sa_family_t)AF_INET6) {
83         inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
84                   ipstr, sizeof(ipstr));
85     } else
86 #endif
87     {
88         inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
89                   sizeof(ipstr));
90     }
91     g_snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port);
92     return mystr_sockaddr;
93 }
94
95 int
96 cmp_sockaddr(
97     struct sockaddr_storage *ss1,
98     struct sockaddr_storage *ss2,
99     int addr_only)
100 {
101     /* if addresses are v4mapped, "unmap" them */
102 #ifdef WORKING_IPV6
103 #ifdef IN6_IS_ADDR_V4MAPPED
104     struct sockaddr_in ss1_v4;
105     struct sockaddr_in ss2_v4;
106
107     if (ss1->ss_family == AF_INET6 &&
108         IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss1)->sin6_addr)) {
109         memset(&ss1_v4, 0, sizeof(struct sockaddr_in));
110         memcpy(&ss1_v4.sin_addr.s_addr,
111                &(((struct sockaddr_in6 *)ss1)->sin6_addr.s6_addr[12]),
112                sizeof(struct in_addr));
113         ss1_v4.sin_family = AF_INET;
114         SS_SET_PORT((struct sockaddr_storage *)&ss1_v4, SS_GET_PORT(ss1));
115         ss1 = (struct sockaddr_storage *)&ss1_v4;
116     }
117
118     if (ss2->ss_family == AF_INET6 &&
119         IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss2)->sin6_addr)) {
120         memset(&ss2_v4, 0, sizeof(struct sockaddr_in));
121         memcpy(&ss2_v4.sin_addr.s_addr,
122                &(((struct sockaddr_in6 *)ss2)->sin6_addr.s6_addr[12]),
123                sizeof(struct in_addr));
124         ss2_v4.sin_family = AF_INET;
125         SS_SET_PORT((struct sockaddr_storage *)&ss2_v4, SS_GET_PORT(ss2));
126         ss2 = (struct sockaddr_storage *)&ss2_v4;
127     }
128 #endif
129 #endif
130
131     if (ss1->ss_family == ss2->ss_family) {
132         if (addr_only) {
133 #ifdef WORKING_IPV6
134             if(ss1->ss_family == (sa_family_t)AF_INET6)
135                 return memcmp(
136                     &((struct sockaddr_in6 *)ss1)->sin6_addr,
137                     &((struct sockaddr_in6 *)ss2)->sin6_addr,
138                     sizeof(((struct sockaddr_in6 *)ss1)->sin6_addr));
139             else
140 #endif
141                 return memcmp(
142                     &((struct sockaddr_in *)ss1)->sin_addr,
143                     &((struct sockaddr_in *)ss2)->sin_addr,
144                     sizeof(((struct sockaddr_in *)ss1)->sin_addr));
145         } else {
146             return memcmp(ss1, ss2, SS_LEN(ss1));
147         }
148     } else {
149         /* compare families to give a total order */
150         if (ss1->ss_family < ss2->ss_family)
151             return -1;
152         else
153             return 1;
154     }
155 }
156