r23792: convert Samba4 to GPLv3
[jelmer/samba4-debian.git] / source / lib / socket / socket_ipv4.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Socket IPv4 functions
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Tridgell 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "lib/socket/socket.h"
26 #include "system/network.h"
27
28 static NTSTATUS ipv4_init(struct socket_context *sock)
29 {
30         int type;
31
32         switch (sock->type) {
33         case SOCKET_TYPE_STREAM:
34                 type = SOCK_STREAM;
35                 break;
36         case SOCKET_TYPE_DGRAM:
37                 type = SOCK_DGRAM;
38                 break;
39         default:
40                 return NT_STATUS_INVALID_PARAMETER;
41         }
42
43         sock->fd = socket(PF_INET, type, 0);
44         if (sock->fd == -1) {
45                 return map_nt_error_from_unix(errno);
46         }
47
48         sock->backend_name = "ipv4";
49
50         return NT_STATUS_OK;
51 }
52
53 static void ipv4_close(struct socket_context *sock)
54 {
55         close(sock->fd);
56 }
57
58 static NTSTATUS ipv4_connect_complete(struct socket_context *sock, uint32_t flags)
59 {
60         int error=0, ret;
61         socklen_t len = sizeof(error);
62
63         /* check for any errors that may have occurred - this is needed
64            for non-blocking connect */
65         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
66         if (ret == -1) {
67                 return map_nt_error_from_unix(errno);
68         }
69         if (error != 0) {
70                 return map_nt_error_from_unix(error);
71         }
72
73         if (!(flags & SOCKET_FLAG_BLOCK)) {
74                 ret = set_blocking(sock->fd, False);
75                 if (ret == -1) {
76                         return map_nt_error_from_unix(errno);
77                 }
78         }
79
80         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
81
82         return NT_STATUS_OK;
83 }
84
85
86 static NTSTATUS ipv4_connect(struct socket_context *sock,
87                              const struct socket_address *my_address, 
88                              const struct socket_address *srv_address,
89                              uint32_t flags)
90 {
91         struct sockaddr_in srv_addr;
92         struct ipv4_addr my_ip;
93         struct ipv4_addr srv_ip;
94         int ret;
95
96         if (my_address && my_address->sockaddr) {
97                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
98                 if (ret == -1) {
99                         return map_nt_error_from_unix(errno);
100                 }
101         } else if (my_address) {
102                 my_ip = interpret_addr2(my_address->addr);
103                 
104                 if (my_ip.addr != 0 || my_address->port != 0) {
105                         struct sockaddr_in my_addr;
106                         ZERO_STRUCT(my_addr);
107 #ifdef HAVE_SOCK_SIN_LEN
108                         my_addr.sin_len         = sizeof(my_addr);
109 #endif
110                         my_addr.sin_addr.s_addr = my_ip.addr;
111                         my_addr.sin_port        = htons(my_address->port);
112                         my_addr.sin_family      = PF_INET;
113                         
114                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
115                         if (ret == -1) {
116                                 return map_nt_error_from_unix(errno);
117                         }
118                 }
119         }
120
121         if (srv_address->sockaddr) {
122                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
123                 if (ret == -1) {
124                         return map_nt_error_from_unix(errno);
125                 }
126         } else {
127                 srv_ip = interpret_addr2(srv_address->addr);
128                 if (!srv_ip.addr) {
129                         return NT_STATUS_BAD_NETWORK_NAME;
130                 }
131                 
132                 ZERO_STRUCT(srv_addr);
133 #ifdef HAVE_SOCK_SIN_LEN
134                 srv_addr.sin_len        = sizeof(srv_addr);
135 #endif
136                 srv_addr.sin_addr.s_addr= srv_ip.addr;
137                 srv_addr.sin_port       = htons(srv_address->port);
138                 srv_addr.sin_family     = PF_INET;
139
140                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
141                 if (ret == -1) {
142                         return map_nt_error_from_unix(errno);
143                 }
144         }
145
146         return ipv4_connect_complete(sock, flags);
147 }
148
149
150 /*
151   note that for simplicity of the API, socket_listen() is also
152   use for DGRAM sockets, but in reality only a bind() is done
153 */
154 static NTSTATUS ipv4_listen(struct socket_context *sock,
155                             const struct socket_address *my_address, 
156                             int queue_size, uint32_t flags)
157 {
158         struct sockaddr_in my_addr;
159         struct ipv4_addr ip_addr;
160         int ret;
161
162         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
163
164         if (my_address->sockaddr) {
165                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
166         } else {
167                 ip_addr = interpret_addr2(my_address->addr);
168                 
169                 ZERO_STRUCT(my_addr);
170 #ifdef HAVE_SOCK_SIN_LEN
171                 my_addr.sin_len         = sizeof(my_addr);
172 #endif
173                 my_addr.sin_addr.s_addr = ip_addr.addr;
174                 my_addr.sin_port        = htons(my_address->port);
175                 my_addr.sin_family      = PF_INET;
176                 
177                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
178         }
179
180         if (ret == -1) {
181                 return map_nt_error_from_unix(errno);
182         }
183
184         if (sock->type == SOCKET_TYPE_STREAM) {
185                 ret = listen(sock->fd, queue_size);
186                 if (ret == -1) {
187                         return map_nt_error_from_unix(errno);
188                 }
189         }
190
191         if (!(flags & SOCKET_FLAG_BLOCK)) {
192                 ret = set_blocking(sock->fd, False);
193                 if (ret == -1) {
194                         return map_nt_error_from_unix(errno);
195                 }
196         }
197
198         sock->state= SOCKET_STATE_SERVER_LISTEN;
199
200         return NT_STATUS_OK;
201 }
202
203 static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
204 {
205         struct sockaddr_in cli_addr;
206         socklen_t cli_addr_len = sizeof(cli_addr);
207         int new_fd;
208
209         if (sock->type != SOCKET_TYPE_STREAM) {
210                 return NT_STATUS_INVALID_PARAMETER;
211         }
212
213         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
214         if (new_fd == -1) {
215                 return map_nt_error_from_unix(errno);
216         }
217
218         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
219                 int ret = set_blocking(new_fd, False);
220                 if (ret == -1) {
221                         close(new_fd);
222                         return map_nt_error_from_unix(errno);
223                 }
224         }
225
226         /* TODO: we could add a 'accept_check' hook here
227          *       which get the black/white lists via socket_set_accept_filter()
228          *       or something like that
229          *       --metze
230          */
231
232         (*new_sock) = talloc(NULL, struct socket_context);
233         if (!(*new_sock)) {
234                 close(new_fd);
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         /* copy the socket_context */
239         (*new_sock)->type               = sock->type;
240         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
241         (*new_sock)->flags              = sock->flags;
242
243         (*new_sock)->fd                 = new_fd;
244
245         (*new_sock)->private_data       = NULL;
246         (*new_sock)->ops                = sock->ops;
247         (*new_sock)->backend_name       = sock->backend_name;
248
249         return NT_STATUS_OK;
250 }
251
252 static NTSTATUS ipv4_recv(struct socket_context *sock, void *buf, 
253                               size_t wantlen, size_t *nread)
254 {
255         ssize_t gotlen;
256
257         *nread = 0;
258
259         gotlen = recv(sock->fd, buf, wantlen, 0);
260         if (gotlen == 0) {
261                 return NT_STATUS_END_OF_FILE;
262         } else if (gotlen == -1) {
263                 return map_nt_error_from_unix(errno);
264         }
265
266         *nread = gotlen;
267
268         return NT_STATUS_OK;
269 }
270
271
272 static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, 
273                               size_t wantlen, size_t *nread, 
274                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
275 {
276         ssize_t gotlen;
277         struct sockaddr_in *from_addr;
278         socklen_t from_len = sizeof(*from_addr);
279         struct socket_address *src;
280         const char *addr;
281         
282         src = talloc(addr_ctx, struct socket_address);
283         if (!src) {
284                 return NT_STATUS_NO_MEMORY;
285         }
286         
287         src->family = sock->backend_name;
288
289         from_addr = talloc(src, struct sockaddr_in);
290         if (!from_addr) {
291                 talloc_free(src);
292                 return NT_STATUS_NO_MEMORY;
293         }
294
295         src->sockaddr = (struct sockaddr *)from_addr;
296
297         *nread = 0;
298
299         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
300                           src->sockaddr, &from_len);
301         if (gotlen == 0) {
302                 talloc_free(src);
303                 return NT_STATUS_END_OF_FILE;
304         } else if (gotlen == -1) {
305                 talloc_free(src);
306                 return map_nt_error_from_unix(errno);
307         }
308
309         src->sockaddrlen = from_len;
310
311         addr = inet_ntoa(from_addr->sin_addr);
312         if (addr == NULL) {
313                 talloc_free(src);
314                 return NT_STATUS_INTERNAL_ERROR;
315         }
316         src->addr = talloc_strdup(src, addr);
317         if (src->addr == NULL) {
318                 talloc_free(src);
319                 return NT_STATUS_NO_MEMORY;
320         }
321         src->port = ntohs(from_addr->sin_port);
322
323         *nread  = gotlen;
324         *_src   = src;
325         return NT_STATUS_OK;
326 }
327
328 static NTSTATUS ipv4_send(struct socket_context *sock, 
329                               const DATA_BLOB *blob, size_t *sendlen)
330 {
331         ssize_t len;
332
333         *sendlen = 0;
334
335         len = send(sock->fd, blob->data, blob->length, 0);
336         if (len == -1) {
337                 return map_nt_error_from_unix(errno);
338         }       
339
340         *sendlen = len;
341
342         return NT_STATUS_OK;
343 }
344
345 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
346                             const DATA_BLOB *blob, size_t *sendlen, 
347                             const struct socket_address *dest_addr)
348 {
349         ssize_t len;
350
351         if (dest_addr->sockaddr) {
352                 len = sendto(sock->fd, blob->data, blob->length, 0, 
353                              dest_addr->sockaddr, dest_addr->sockaddrlen);
354         } else {
355                 struct sockaddr_in srv_addr;
356                 struct ipv4_addr addr;
357                 
358                 ZERO_STRUCT(srv_addr);
359 #ifdef HAVE_SOCK_SIN_LEN
360                 srv_addr.sin_len         = sizeof(srv_addr);
361 #endif
362                 addr                     = interpret_addr2(dest_addr->addr);
363                 if (addr.addr == 0) {
364                         return NT_STATUS_HOST_UNREACHABLE;
365                 }
366                 srv_addr.sin_addr.s_addr = addr.addr;
367                 srv_addr.sin_port        = htons(dest_addr->port);
368                 srv_addr.sin_family      = PF_INET;
369                 
370                 *sendlen = 0;
371                 
372                 len = sendto(sock->fd, blob->data, blob->length, 0, 
373                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
374         }
375         if (len == -1) {
376                 return map_nt_error_from_unix(errno);
377         }       
378
379         *sendlen = len;
380
381         return NT_STATUS_OK;
382 }
383
384 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
385 {
386         set_socket_options(sock->fd, option);
387         return NT_STATUS_OK;
388 }
389
390 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
391 {
392         struct sockaddr_in peer_addr;
393         socklen_t len = sizeof(peer_addr);
394         struct hostent *he;
395         int ret;
396
397         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
398         if (ret == -1) {
399                 return NULL;
400         }
401
402         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
403         if (he == NULL) {
404                 return NULL;
405         }
406
407         return talloc_strdup(mem_ctx, he->h_name);
408 }
409
410 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
411 {
412         struct sockaddr_in *peer_addr;
413         socklen_t len = sizeof(*peer_addr);
414         const char *addr;
415         struct socket_address *peer;
416         int ret;
417         
418         peer = talloc(mem_ctx, struct socket_address);
419         if (!peer) {
420                 return NULL;
421         }
422         
423         peer->family = sock->backend_name;
424         peer_addr = talloc(peer, struct sockaddr_in);
425         if (!peer_addr) {
426                 talloc_free(peer);
427                 return NULL;
428         }
429
430         peer->sockaddr = (struct sockaddr *)peer_addr;
431
432         ret = getpeername(sock->fd, peer->sockaddr, &len);
433         if (ret == -1) {
434                 talloc_free(peer);
435                 return NULL;
436         }
437
438         peer->sockaddrlen = len;
439
440         addr = inet_ntoa(peer_addr->sin_addr);
441         if (addr == NULL) {
442                 talloc_free(peer);
443                 return NULL;
444         }
445         peer->addr = talloc_strdup(peer, addr);
446         if (!peer->addr) {
447                 talloc_free(peer);
448                 return NULL;
449         }
450         peer->port = ntohs(peer_addr->sin_port);
451
452         return peer;
453 }
454
455 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
456 {
457         struct sockaddr_in *local_addr;
458         socklen_t len = sizeof(*local_addr);
459         const char *addr;
460         struct socket_address *local;
461         int ret;
462         
463         local = talloc(mem_ctx, struct socket_address);
464         if (!local) {
465                 return NULL;
466         }
467         
468         local->family = sock->backend_name;
469         local_addr = talloc(local, struct sockaddr_in);
470         if (!local_addr) {
471                 talloc_free(local);
472                 return NULL;
473         }
474
475         local->sockaddr = (struct sockaddr *)local_addr;
476
477         ret = getsockname(sock->fd, local->sockaddr, &len);
478         if (ret == -1) {
479                 talloc_free(local);
480                 return NULL;
481         }
482
483         local->sockaddrlen = len;
484
485         addr = inet_ntoa(local_addr->sin_addr);
486         if (addr == NULL) {
487                 talloc_free(local);
488                 return NULL;
489         }
490         local->addr = talloc_strdup(local, addr);
491         if (!local->addr) {
492                 talloc_free(local);
493                 return NULL;
494         }
495         local->port = ntohs(local_addr->sin_port);
496
497         return local;
498 }
499 static int ipv4_get_fd(struct socket_context *sock)
500 {
501         return sock->fd;
502 }
503
504 static NTSTATUS ipv4_pending(struct socket_context *sock, size_t *npending)
505 {
506         int value = 0;
507         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
508                 *npending = value;
509                 return NT_STATUS_OK;
510         }
511         return map_nt_error_from_unix(errno);
512 }
513
514 static const struct socket_ops ipv4_ops = {
515         .name                   = "ipv4",
516         .fn_init                = ipv4_init,
517         .fn_connect             = ipv4_connect,
518         .fn_connect_complete    = ipv4_connect_complete,
519         .fn_listen              = ipv4_listen,
520         .fn_accept              = ipv4_accept,
521         .fn_recv                = ipv4_recv,
522         .fn_recvfrom            = ipv4_recvfrom,
523         .fn_send                = ipv4_send,
524         .fn_sendto              = ipv4_sendto,
525         .fn_pending             = ipv4_pending,
526         .fn_close               = ipv4_close,
527
528         .fn_set_option          = ipv4_set_option,
529
530         .fn_get_peer_name       = ipv4_get_peer_name,
531         .fn_get_peer_addr       = ipv4_get_peer_addr,
532         .fn_get_my_addr         = ipv4_get_my_addr,
533         .fn_get_fd              = ipv4_get_fd
534 };
535
536 const struct socket_ops *socket_ipv4_ops(enum socket_type type)
537 {
538         return &ipv4_ops;
539 }