ctdb-common: Protocol argument must be in host order for socket() call
[samba.git] / ctdb / common / system_common.c
1 /* 
2    ctdb system specific code to manage raw sockets on linux
3
4    Copyright (C) Ronnie Sahlberg  2007
5    Copyright (C) Andrew Tridgell  2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "replace.h"
22 #include "system/network.h"
23
24 #include "lib/util/debug.h"
25
26 #include "protocol/protocol.h"
27
28 #include "common/logging.h"
29 #include "common/system.h"
30
31 /*
32   uint16 checksum for n bytes
33  */
34 uint32_t uint16_checksum(uint16_t *data, size_t n)
35 {
36         uint32_t sum=0;
37         while (n>=2) {
38                 sum += (uint32_t)ntohs(*data);
39                 data++;
40                 n -= 2;
41         }
42         if (n == 1) {
43                 sum += (uint32_t)ntohs(*(uint8_t *)data);
44         }
45         return sum;
46 }
47
48 /*
49   see if we currently have an interface with the given IP
50
51   we try to bind to it, and if that fails then we don't have that IP
52   on an interface
53  */
54 bool ctdb_sys_have_ip(ctdb_sock_addr *_addr)
55 {
56         int s;
57         int ret;
58         ctdb_sock_addr __addr = *_addr;
59         ctdb_sock_addr *addr = &__addr;
60         socklen_t addrlen = 0;
61
62         switch (addr->sa.sa_family) {
63         case AF_INET:
64                 addr->ip.sin_port = 0;
65                 addrlen = sizeof(struct sockaddr_in);
66                 break;
67         case AF_INET6:
68                 addr->ip6.sin6_port = 0;
69                 addrlen = sizeof(struct sockaddr_in6);
70                 break;
71         }
72
73         s = socket(addr->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
74         if (s == -1) {
75                 return false;
76         }
77
78         ret = bind(s, (struct sockaddr *)addr, addrlen);
79
80         close(s);
81         return ret == 0;
82 }
83
84
85 /* find which interface an ip address is currently assigned to */
86 char *ctdb_sys_find_ifname(ctdb_sock_addr *addr)
87 {
88         int s;
89         int size;
90         struct ifconf ifc;
91         char *ptr;
92
93         s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
94         if (s == -1) {
95                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
96                          strerror(errno)));
97                 return NULL;
98         }
99
100
101         size = sizeof(struct ifreq);
102         ifc.ifc_buf = NULL;
103         ifc.ifc_len = size;
104
105         while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
106                 size *= 2;
107
108                 free(ifc.ifc_buf);      
109                 ifc.ifc_len = size;
110                 ifc.ifc_buf = malloc(size);
111                 memset(ifc.ifc_buf, 0, size);
112                 if (ioctl(s, SIOCGIFCONF, (caddr_t)&ifc) < 0) {
113                         DEBUG(DEBUG_CRIT,("Failed to read ifc buffer from socket\n"));
114                         free(ifc.ifc_buf);      
115                         close(s);
116                         return NULL;
117                 }
118         }
119
120         for (ptr =(char *)ifc.ifc_buf; ptr < ((char *)ifc.ifc_buf) + ifc.ifc_len; ) {
121                 char *ifname;
122                 struct ifreq *ifr;
123
124                 ifr = (struct ifreq *)ptr;
125
126 #ifdef HAVE_SOCKADDR_LEN
127                 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
128                         ptr += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
129                 } else {
130                         ptr += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
131                 }
132 #else
133                 ptr += sizeof(struct ifreq);
134 #endif
135
136                 if (ifr->ifr_addr.sa_family != addr->sa.sa_family) {
137                         continue;
138                 }
139
140                 switch (addr->sa.sa_family) {
141                 case AF_INET:
142
143
144                         if (memcmp(&addr->ip.sin_addr, &((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr, sizeof(addr->ip.sin_addr))) {
145                                 continue;
146                         }
147                         break;
148                 case AF_INET6:
149                         if (memcmp(&addr->ip6.sin6_addr, &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr, sizeof(addr->ip6.sin6_addr))) {
150                                 continue;
151                         }
152                         break;
153                 }
154
155                 ifname = strdup(ifr->ifr_name);
156                 free(ifc.ifc_buf);      
157                 close(s);
158                 return ifname;
159         }
160
161
162         free(ifc.ifc_buf);      
163         close(s);
164
165         return NULL;
166 }