1 /*
2 * fiked - a fake IKE PSK+XAUTH daemon based on vpnc
3 * Copyright (C) 2005, Daniel Roethlisberger <daniel@roe.ch>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/
17 *
18 * $Id: datagram.c 103 2005-12-18 16:28:08Z roe $
19 */
20
21 #include "datagram.h"
22 #include "log.h"
23 #include "mem.h"
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 /*
35 * Create a new datagram instance of given size.
36 * If size is 0, make it as large as supported by UDP.
37 */
datagram_new(size_t size)38 datagram * datagram_new(size_t size)
39 {
40 if(size == 0)
41 size = UDP_DGM_MAXSIZE;
42 datagram *dgm = NULL;
43 mem_allocate(&dgm, sizeof(datagram));
44 memset(dgm, 0, sizeof(datagram));
45 dgm->len = size;
46 mem_allocate(&dgm->data, dgm->len);
47 memset(dgm->data, 0, sizeof(dgm->len));
48 return dgm;
49 }
50
51 /*
52 * Free a datagram instance.
53 */
datagram_free(datagram * dgm)54 void datagram_free(datagram *dgm)
55 {
56 if(dgm) {
57 mem_free(&dgm->data);
58 free(dgm);
59 }
60 }
61
62 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63
64 /*
65 * Open a UDP socket on the given port.
66 * Will quit on errors.
67 */
udp_socket_new(uint16_t port)68 udp_socket * udp_socket_new(uint16_t port)
69 {
70 udp_socket *s = NULL;
71 mem_allocate(&s, sizeof(udp_socket));
72 s->port = port;
73 s->fd = socket(PF_INET, SOCK_DGRAM, 0);
74 if(s->fd < 0) {
75 fprintf(stderr, "FATAL: socket(udp) returned %d: %s (%d)\n",
76 s->fd, strerror(errno), errno);
77 exit(-1);
78 }
79
80 struct sockaddr_in sa;
81 sa.sin_family = AF_INET;
82 sa.sin_port = htons(s->port);
83 sa.sin_addr.s_addr = htonl(INADDR_ANY);
84 int ret = bind(s->fd, (struct sockaddr *)&sa, sizeof(sa));
85 if(ret < 0) {
86 fprintf(stderr, "FATAL: bind(%d/udp) returned %d: %s (%d)\n",
87 s->port, ret, strerror(errno), errno);
88 exit(-1);
89 }
90
91 return s;
92 }
93
94 /*
95 * Close UDP socket.
96 */
udp_socket_free(udp_socket * s)97 void udp_socket_free(udp_socket *s)
98 {
99 if(s) {
100 close(s->fd);
101 free(s);
102 }
103 }
104
105 /*
106 * Receive next incoming UDP datagram on socket s.
107 * Blocks until a datagram is received.
108 */
udp_socket_recv(udp_socket * s)109 datagram * udp_socket_recv(udp_socket *s)
110 {
111 char buf[UDP_DGM_MAXSIZE];
112 struct sockaddr_in sa;
113 socklen_t sa_len = sizeof(sa);
114 int ret = recvfrom(s->fd, buf, sizeof(buf), 0,
115 (struct sockaddr *)&sa, &sa_len);
116 if(ret < 0) {
117 log_printf(NULL, "ERROR: recvfrom(%d) returned %d: %s (%d)\n",
118 s->fd, ret, strerror(errno), errno);
119 }
120
121 datagram *dgm = datagram_new(ret);
122 memcpy(dgm->data, buf, dgm->len);
123 dgm->peer_addr = sa;
124
125 return dgm;
126 }
127
128 /*
129 * Send a UDP datagram onto socket s.
130 */
udp_socket_send(udp_socket * s,datagram * dgm)131 void udp_socket_send(udp_socket *s, datagram *dgm)
132 {
133 int ret = sendto(s->fd, dgm->data, dgm->len, 0,
134 (struct sockaddr*)&dgm->peer_addr, sizeof(dgm->peer_addr));
135 if(ret < 0) {
136 log_printf(NULL, "ERROR: sendto(%d to %s:%d) returned %d: %s (%d)\n",
137 s->fd, inet_ntoa(dgm->peer_addr.sin_addr),
138 ntohs(dgm->peer_addr.sin_port),
139 ret, strerror(errno), errno);
140 }
141 }
142
143