chiark / gitweb /
test: udp-preload: Beginning of actual implementation
[secnet.git] / test / udp-preload.c
1 /*
2  *  libauthbind.c - bind(2)-redirector library for authbind
3  *
4  *  authbind is Copyright (C) 1998 Ian Jackson
5  * 
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  * 
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  * 
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software Foundation,
18  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
19  * 
20  */
21
22 #define _GNU_SOURCE
23
24 #include <dlfcn.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <sys/socket.h>
33 #include <sys/wait.h>
34 #include <netinet/in.h>
35
36 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
37 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
38
39 typedef void anyfn_type(void);
40
41 static anyfn_type *find_any(const char *name) {
42   static const char *dlerr;
43   anyfn_type *kv;
44
45   kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
46   dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
47   STDERRSTR_CONST("libauthbind: error finding original version of ");
48   STDERRSTR_STRING(name);
49   STDERRSTR_CONST(": ");
50   STDERRSTR_STRING(dlerr);
51   STDERRSTR_STRING("\n");
52   errno= ENOSYS;
53   return 0;
54 }
55
56 #define socket_args int domain, int type, int protocol
57 #define bind_args   int fd, const struct sockaddr *addr, socklen_t addrlen
58 #define WRAPS(X)                                \
59     X(socket, (domain,type,protocol))           \
60     X(bind,   (fd,addr,addrlen))
61
62 #define DEF_OLD(fn,args)                                \
63   typedef int fn##_fn_type(fn##_args);                  \
64   static int find_##fn(fn##_args);                      \
65   static fn##_fn_type find_##fn, *old_##fn=find_##fn;   \
66   static int find_##fn(fn##_args) {                     \
67     anyfn_type *anyfn;                                  \
68     anyfn= find_any(#fn); if (!anyfn) return -1;        \
69     old_##fn= (fn##_fn_type*)anyfn;                     \
70     return old_##fn args;                               \
71   }
72
73 WRAPS(DEF_OLD)
74
75 #define WRAP(fn) int fn(fn##_args)
76
77 typedef struct{
78     int af;
79     union {
80         struct sockaddr_in v4;
81         struct sockaddr_in6 v6;
82     } bound;
83 } fdinfo;
84 static fdinfo **table;
85 static int tablesz;
86
87 static fdinfo *lookup(int fd) {
88     if (fd>=tablesz) return 0;
89     return table[fd];
90 }
91
92 static int chkaddr(fdinfo *ent,
93                    const struct sockaddr *addr, socklen_t addrlen) {
94     if (addr->sa_family!=ent->af) { errno=EAFNOSUPPORT; return -1; }
95     socklen_t expectlen;
96     switch (addr->sa_family) {
97     case AF_INET:  expectlen=sizeof(ent->bound.v4); break;
98     case AF_INET6: expectlen=sizeof(ent->bound.v6); break;
99     default: abort();
100     }
101     if (addrlen!=expectlen) { errno=EINVAL; return -1; }
102     return 0;
103 }
104
105 WRAP(socket) {
106     if (!((domain==AF_INET || domain==AF_INET6) &&
107           type==SOCK_DGRAM))
108         return old_socket(domain,type,protocol);
109     int fd=socket(AF_UNIX,SOCK_DGRAM,0);
110     if (fd<0) return fd;
111     if (fd>=tablesz) {
112         int newsz=(fd+1)*2;
113         table=realloc(table,newsz*sizeof(*table));
114         if (!table) goto fail;
115         while (tablesz<newsz) table[tablesz++]=0;
116     }
117     free(table[fd]);
118     table[fd]=malloc(sizeof(*table[fd]));
119     if (!table[fd]) goto fail;
120     table[fd]->af=domain;
121     table[fd]->bound.v4.sin_family=0;
122     return fd;
123
124  fail:
125     close(fd);
126     return -1;
127 }
128
129 WRAP(bind) {
130     fdinfo *ent=lookup(fd);
131     if (!ent) return bind(fd,addr,addrlen);
132     if (chkaddr(ent,addr,addrlen)) return -1;
133     memset(&ent->bound,0,sizeof(ent->bound));
134     memcpy(&ent->bound,addr,addrlen);
135     return 0;
136 }