added (unused) rules.rc parser to so. it will be used later.
[umfw.git] / src / tumfw.c
blobd9db0b79960464695c2235f8b604e4d9026d99f3
1 /*
2 * based on TSOCKS - Wrapper library for transparent SOCKS
3 * TSOCKS Copyright (C) 2000 Shaun Clowes
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "config.h"
22 /* Global configuration variables */
23 char *progname = "libtumfw"; /* Name used in err msgs */
25 /* Header Files */
26 #include <arpa/inet.h>
27 #include <dlfcn.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <netinet/in.h>
31 #include <pwd.h>
32 #include <stdarg.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <sys/poll.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/select.h>
42 #include <sys/socket.h>
43 #include <sys/stat.h>
44 #include <sys/un.h>
45 #include <unistd.h>
47 #include "common.h"
48 #include "tumfw.h"
49 #include "uproto.h"
51 #include "common.c"
53 /* global declarations */
54 static int (*realconnect) (CONNECT_SIGNATURE);
55 static int (*realbind) (BIND_SIGNATURE);
56 static ssize_t (*realsendto) (SENDTO_SIGNATURE);
59 /* exported function prototypes */
60 void _init (void);
61 int connect (CONNECT_SIGNATURE);
62 int bind (BIND_SIGNATURE);
63 ssize_t sendto (SENDTO_SIGNATURE);
66 static int suid = 0;
69 /*****************************************************************************/
70 #include "rulecache.c"
72 #ifdef OPT_USE_RULE_PARSER
73 #include "ruleparser.c"
74 #endif
77 /*****************************************************************************/
78 static int getEnvironment (void) {
79 static int done = 0;
80 int loglevel = LOGMSG_ERR;
81 char *logfile = NULL;
82 char *env;
84 if (done) return 0;
85 if ((env = getenv("TUMFW_DEBUG"))) loglevel = atoi(env);
86 if (((env = getenv("TUMFW_DEBUG_FILE"))) && !suid) logfile = env;
87 setLogOptions(loglevel, logfile, 1);
88 #ifdef OPT_USE_RULE_PARSER
89 initRuleParser();
90 #endif
91 done = 1;
92 return 0;
96 static int getConfig (void) {
97 static int done = 0;
99 #ifdef OPT_USE_RULE_PARSER
100 updateRuleParser();
101 #endif
103 if (done) return 0;
104 done = 1;
105 return 0;
110 * 0: all ok
111 * 1: invalid domain
112 * 2: invalid type
114 static int checkFDandAddr (const char *opname, int __fd, const struct sockaddr_in *connaddr, uint8_t *type) {
115 int sock_type = -1;
116 int sock_type_len = sizeof(sock_type);
118 /* if this isn't an INET socket we can't handle it, just call the real op */
119 if (connaddr->sin_family != AF_INET) {
120 logMsg(LOGMSG_DEBUG, "%s: isn't an AF_INET, ignoring\n", opname);
121 return 1;
124 /* get the type of the socket */
125 getsockopt(__fd, SOL_SOCKET, SO_TYPE, (void *)&sock_type, (void *)&sock_type_len);
127 if (sock_type != SOCK_STREAM && sock_type != SOCK_DGRAM) {
128 logMsg(LOGMSG_DEBUG, "%s: isn't a TCP/UDP, ignoring\n", opname);
129 return 2;
132 *type = (sock_type == SOCK_STREAM)?IPCQ_PROTO_TCP:IPCQ_PROTO_UDP;
134 /* if we haven't initialized yet, do it now */
135 getConfig();
137 return 0;
141 /* 0: can't */
142 static int askAllowConnect (const struct in_addr *in, uint16_t port, uint8_t proto, uint8_t action) {
143 int oerrno = errno;
144 uint32_t *ip = (uint32_t *)in;
146 if (!realbind || !realconnect || !realsendto) return 1; /* no binds -- no checks */
148 if (((*ip>>24)&0xff) == 127) return 1; /* localhost always allowed */
150 tSessionRule *rule = findRule(*ip, port, proto);
151 if (rule) return rule->allow;
153 int ufd = socket(AF_UNIX, SOCK_STREAM, 0);
154 if (ufd == -1) {
155 logMsg(LOGMSG_DEBUG, "can't create umfw socket\n");
156 errno = oerrno;
157 return 1; /* alas, no fd -- no checks */
160 struct sockaddr_un srv;
161 srv.sun_family = AF_UNIX;
162 strcpy(srv.sun_path, UNIX_SOCKET_PATH);
164 if (realbind(ufd, (struct sockaddr *)&srv, sizeof(struct sockaddr_un))) {
165 logMsg(LOGMSG_DEBUG, "can't bind umfw socket\n");
166 goto error;
169 if (realconnect(ufd, (struct sockaddr *)&srv, sizeof(struct sockaddr_un))) {
170 logMsg(LOGMSG_DEBUG, "can't connect to umfw socket\n");
171 goto error;
174 tIPCQuery sbuf;
175 sbuf.version = UPROTO_VERSION;
176 sbuf.pid = getpid();
177 sbuf.ip = htonl(*ip);
178 sbuf.port = htons(port);
179 sbuf.proto = proto;
180 sbuf.action = action;
181 if (send(ufd, &sbuf, sizeof(sbuf), MSG_NOSIGNAL) != sizeof(sbuf)) {
182 logMsg(LOGMSG_DEBUG, "can't send to umfw socket\n");
183 goto error;
186 tIPCReply rbuf;
188 do {
189 int r;
190 if ((r = recv(ufd, &rbuf, sizeof(rbuf), MSG_WAITALL)) != sizeof(rbuf)) {
191 logMsg(LOGMSG_DEBUG, "can't read from umfw socket\n");
192 if (errno == EAGAIN || errno == EINTR) {
193 logMsg(LOGMSG_DEBUG, "umfw socket: restarting\n");
195 goto error;
196 } else break;
197 } while(1);
199 if (rbuf.version != UPROTO_VERSION) {
200 logMsg(LOGMSG_DEBUG, "umfw socket: invalid version read\n");
201 goto error;
204 close(ufd);
206 if (rbuf.flags) {
207 /* new session/permanent rule */
208 addRule(*ip, port, rbuf.allow, rbuf.flags);
209 logMsg(LOGMSG_DEBUG, "umfw socket: new session rule: %08x %u %u %02x\n", *ip, port, rbuf.allow, rbuf.flags);
212 errno = oerrno;
213 return rbuf.allow == IPCR_ALLOW;
215 error:
216 /* alas, server error -- no checks */
217 close(ufd);
218 errno = oerrno;
219 return 1;
223 #define CHECK_SYMBOL(name) \
225 getEnvironment(); \
226 if (real##name == NULL) { \
227 logMsg(LOGMSG_ERR, "unresolved symbol: %s\n", #name); \
228 return -1; \
232 #define IP_BYTES(n) \
233 (uint32_t)(n) & 0xff, \
234 (((uint32_t)(n))>>8) & 0xff, \
235 (((uint32_t)(n))>>16) & 0xff, \
236 (((uint32_t)(n))>>24) & 0xff
238 static void logAction (const char *action, const struct in_addr *ip, uint16_t port) {
239 logMsg(LOGMSG_DEBUG, "*%s: %u.%u.%u.%u:%u\n", action, IP_BYTES(ip->s_addr), (unsigned int)htons(port));
243 int connect (CONNECT_SIGNATURE) {
244 struct sockaddr_in *connaddr;
245 unsigned char type;
247 CHECK_SYMBOL(connect);
248 connaddr = (struct sockaddr_in *)__addr;
249 if (checkFDandAddr("connect", __fd, connaddr, &type)) goto skipcheck;
250 logAction("connect", &connaddr->sin_addr, connaddr->sin_port);
251 if (!askAllowConnect(&connaddr->sin_addr, connaddr->sin_port, type, IPCQ_ACTION_CONNECT)) {
252 errno = ECONNREFUSED;
253 return -1;
255 skipcheck:
256 return realconnect(__fd, __addr, __len);
260 int bind (BIND_SIGNATURE) {
261 struct sockaddr_in *connaddr;
262 unsigned char type;
264 CHECK_SYMBOL(bind);
265 connaddr = (struct sockaddr_in *)__addr;
266 if (checkFDandAddr("bind", __fd, connaddr, &type)) goto skipcheck;
267 logAction("bind", &connaddr->sin_addr, connaddr->sin_port);
268 if (!askAllowConnect(&connaddr->sin_addr, connaddr->sin_port, type, IPCQ_ACTION_BIND)) {
269 errno = EADDRNOTAVAIL;
270 return -1;
272 skipcheck:
273 return realbind(__fd, __addr, __len);
277 ssize_t sendto (SENDTO_SIGNATURE) {
278 const struct sockaddr_in *connaddr;
279 unsigned char type;
281 CHECK_SYMBOL(sendto);
282 if (!__dest_addr) goto skipcheck; /* no dest addr -- nothing to check */
283 connaddr = (struct sockaddr_in *)__dest_addr;
284 if (checkFDandAddr("sendto", __fd, connaddr, &type)) goto skipcheck;
285 logAction("sendto", &connaddr->sin_addr, connaddr->sin_port);
286 if (!askAllowConnect(&connaddr->sin_addr, connaddr->sin_port, type, IPCQ_ACTION_SENDTO)) {
287 errno = ENOTCONN;
288 return -1;
290 skipcheck:
291 return realsendto(__fd, __buf, __len, __flags, __dest_addr, __addrlen);
296 * We could do all our initialization here, but to be honest
297 * most programs that are run won't use our services, so
298 * we do our general initialization on first call
300 void _init (void) {
301 /* determine the logging level */
302 suid = (getuid() != geteuid());
303 /* get 'real' pointers */
304 realconnect = dlsym(RTLD_NEXT, "connect");
305 realbind = dlsym(RTLD_NEXT, "bind");
306 realsendto = dlsym(RTLD_NEXT, "sendto");