-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsock.c
172 lines (153 loc) · 5.13 KB
/
sock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* sock.c
* Copyright (C) 2005-2008 Tillmann Werner <[email protected]>
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "honeytrap.h"
#include "ipqmon.h"
#include "logging.h"
#include "nfqmon.h"
#include "signals.h"
#include "sock.h"
#include "tcpip.h"
/* returns a bound socket matching a connection request *
* sets verdict on request packet if ipq or nfq was used and the port is already bound *
* in the latter case, -1 is returned */
int get_boundsock(struct sockaddr_in *server_addr, uint16_t port, int type) {
int fd, sockopt;
#ifdef USE_IPQ_MON
int status;
#endif
if ((type != SOCK_DGRAM) && (type != SOCK_STREAM)) {
logmsg(LOG_ERR, 1, "Error - Socket type %d not supported.\n", type);
exit(EXIT_FAILURE);
}
if (!(fd = socket(AF_INET, type, 0))) {
logmsg(LOG_ERR, 1, "Error - Could not create socket: %m.\n");
exit(EXIT_FAILURE);
}
sockopt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0)
logmsg(LOG_WARN, 1, "Warning - Unable to set SO_REUSEADDR for server socket.\n");
bzero((char *) server_addr, sizeof(struct sockaddr_in));
server_addr->sin_family = AF_INET;
server_addr->sin_addr.s_addr = bind_address.s_addr;
server_addr->sin_port = port;
if ((bind(fd, (struct sockaddr *) server_addr, sizeof(struct sockaddr_in))) != 0) {
/* we already got one server process */
logmsg(LOG_DEBUG, 1, "Unable to bind to port %u/tcp: %m.\n", ntohs(port));
#ifdef USE_IPQ_MON
/* hand packet processing back to the kernel */
if ((status = ipq_set_verdict(h, packet->packet_id, NF_ACCEPT, 0, NULL)) < 0) {
logmsg(LOG_ERR, 1, "Error - Could not set verdict on packet: %s.\n", ipq_errstr());
ipq_destroy_handle(h);
exit(EXIT_FAILURE);
}
logmsg(LOG_DEBUG, 1, "IPQ - Successfully set verdict on packet.\n");
return(-1);
#else
#ifdef USE_NFQ_MON
/* hand packet processing back to the kernel */
/* nfq_set_verdict()'s return value is undocumented,
* but digging the source of libnetfilter_queue and libnfnetlink reveals
* that it's just the passed-through value of a sendmsg() */
if (nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL) == -1) {
logmsg(LOG_ERR, 1, "Error - Could not set verdict on packet.\n");
nfq_destroy_queue(qh);
exit(EXIT_FAILURE);
}
logmsg(LOG_DEBUG, 1, "NFQ - Successfully set verdict on packet.\n");
/* a dynamic server is already present */
close(fd);
return(-1);
#else
/* if bind() did not fail for 'port already in use' but for some other reason,
* we're in troubles and want a verbose error message */
if (errno != 98) logmsg(LOG_NOISY, 1, "Warning - Could not bind to port %u/tcp: %m.\n", ntohs(port));
exit(EXIT_FAILURE);
#endif
#endif
}
logmsg(LOG_DEBUG, 1, "Socket created, file descriptor is %d.\n", fd);
return(fd);
}
/* perform a non-blocking connect() with a given timeout
* always use this function instead of connect()
* or signal processing might get delayed */
int nb_connect(int sock_fd, const struct sockaddr * sockaddr, socklen_t slen, int sec) {
int flags, rv, error;
struct timeval timeout;
fd_set rfds, wfds;
socklen_t len;
flags = 0;
/* safe fd flags and set socket to non-blocking */
if ((flags = fcntl(sock_fd, F_GETFL, 0) < 0)) return(-1);
if (fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK) < 0) return(-1);
/* try an immediate connect */
errno = 0;
error = 0;
if ((rv = connect(sock_fd, sockaddr, slen)) < 0)
if (errno != EINPROGRESS) return(-1);
if (rv != 0) {
/* do a non-blocking connect */
FD_ZERO(&rfds);
FD_SET(sigpipe[0], &rfds);
FD_SET(sock_fd, &rfds);
wfds = rfds;
timeout.tv_sec = sec;
timeout.tv_usec = 0;
switch (select(MAX(sigpipe[0], sock_fd) + 1, &rfds, &wfds, NULL, &timeout)) {
case -1:
if (errno == EINPROGRESS) break;
if (errno == EINTR) {
if (check_sigpipe() == -1) exit(EXIT_FAILURE);
break;
}
close(sock_fd);
errno = ETIMEDOUT;
return(-1);
case 0:
/* timeout */
close(sock_fd);
errno = ETIMEDOUT;
return(0);
default:
if (FD_ISSET(sigpipe[0], &rfds) && (check_sigpipe() == -1)) {
logmsg(LOG_ERR, 1, "Error - Signal handling failed in dynamic server process.\n");
exit(EXIT_FAILURE);
}
if (FD_ISSET(sock_fd, &rfds) || FD_ISSET(sock_fd, &wfds)) {
len = sizeof(error);
if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) return(-1);
if (error) {
errno = error;
return(-1);
}
}
}
}
if (fcntl(sock_fd, F_SETFL, flags) < 0) return(-1);
if (error) {
errno = error;
return(-1);
}
return(sock_fd);
}