2 * userv service (or standalone program)
3 * for per-user IP subranges.
5 * This is invoked as root, directly from userv.
6 * Its arguments are supposed to be, in order:
7 * <base-prefix>/<base-prefix-len>
8 * Specifies the base address and prefix to restrict the
10 * <gid-min>-<gid-max>:<gid-add>/<gid-mask>[,...]
11 * The ranges specified by <gid-min> are checked <gid-max> until
12 * one is found which matches at least one gid in USERV_GID.
13 * Then the gid will have <gid-add> added to it and will then be
14 * masked so that it is <gid-mask> long (higher set bits are
15 * discarded). The result is added to the base prefix. It is an
16 * error for no gid to match. Alternatively, if this argument
17 * is `*' then USERV_GID is not checked.
18 * -- Indicates that the remaining arguments are user-supplied
19 * and therefore untrusted.
20 * <local-addr>,<peer-addr>,<mtu>,<proto>
21 * As for slattach. Supported protocols are slip, cslip, and
22 * adaptive. Alternatively, set to `debug' to print debugging
23 * info. <local-addr> is address of the interface on chiark;
24 * <peer-addr> is the address of the point-to-point peer.
25 * <prefix>/<mask>,<prefix>/<mask>,...
26 * List of additional routes to add for this interface.
27 * May be the empty argument.
29 * Should be run from userv with no-disconnect-hup.
42 static const char *proto
;
43 static unsigned long baseprefix
, basemask
;
44 static unsigned long localaddr
, peeraddr
, mtu
;
46 static struct exroute
{
47 unsigned long prefix
, mask
;
48 char prefixtxt
[ATXTLEN
], masktxt
[ATXTLEN
];
49 } exroutes
[MAXEXROUTES
];
51 char localtxt
[ATXTLEN
];
52 char peertxt
[ATXTLEN
];
54 static void fatal(const char *msg
) {
55 fprintf(stderr
,"userv-ipif: service: fatal error: %s\n",msg
);
59 static void sysfatal(const char *msg
) {
60 fprintf(stderr
,"userv-ipif: service: fatal system error: %s: %s\n",
61 msg
, strerror(errno
));
65 static void badusage(void) {
66 fputs("userv-ipif: service: bad usage or permission denied\n",stderr
);
70 static char *ip2txt(unsigned long addr
, char *buf
) {
71 sprintf(buf
, "%lu.%lu.%lu.%lu",
79 static unsigned long eat_number(const char **argp
, const char *what
,
80 unsigned long min
, unsigned long max
,
81 const char *endchars
, int *endchar_r
) {
82 /* If !endchars then the endchar must be a nul, otherwise it may be
83 * a nul (resulting in *argp set to 0) or something else (*argp set
84 * to point to after delim, *endchar_r set to delim).
85 * *endchar_r may be 0.
91 if (!*argp
) { fprintf(stderr
,"missing number %s\n",what
); badusage(); }
92 rv
= strtoul(*argp
,&ep
,0);
94 if (!endchars
) { fprintf(stderr
,"junk after number %s\n",what
); badusage(); }
95 if (!strchr(endchars
,endchar
)) {
96 fprintf(stderr
,"invalid delimiter %c after number %s: expected %s (or none?)\n",
97 endchar
,what
,endchars
);
104 if (endchar_r
) *endchar_r
= endchar
;
105 if (rv
< min
|| rv
> max
) {
106 fprintf(stderr
,"number %s value %lu out of range %lu..%lu",
113 static void addrnet_mustbein(const char *what
,
114 unsigned long prefix
, unsigned long mask
,
115 unsigned long mprefix
, unsigned long mmask
) {
116 if (!(~mask
& mmask
) && (prefix
& mmask
) == mprefix
) return;
117 fprintf(stderr
, "%s %08lx/%08lx not in required subspace %08lx/%08lx\n",
118 what
, prefix
, mask
, mprefix
, mmask
);
122 static void addrnet_mustdiffer(const char *w1
, unsigned long p1
, unsigned long m1
,
123 const char *w2
, unsigned long p2
, unsigned long m2
) {
127 if ((p1
& mask
) != (p2
& mask
)) return;
128 fprintf(stderr
, "%s %08lx/%08lx overlaps/clashes with %s %08lx/%08lx",
133 static unsigned long eat_addr(const char **argp
, const char *what
,
134 unsigned long mprefix
, unsigned long mmask
,
135 const char *endchars
, int *endchar_r
) {
140 assert(!(~mmask
& mprefix
));
146 sprintf(whatbuf
,"%s byte #%d",what
,i
);
147 rv
|= eat_number(argp
,whatbuf
, 0,255, i
<3 ?
"." : endchars
, endchar_r
);
150 addrnet_mustbein(what
,rv
,~0UL, mprefix
,mmask
);
154 static void eat_prefixmask(const char **argp
, const char *what
,
155 unsigned long mprefix
, unsigned long mmask
,
156 const char *endchars
, int *endchar_r
,
157 unsigned long *prefix_r
, unsigned long *mask_r
, int *len_r
) {
158 /* mask_r and len_r may be 0 */
161 unsigned long prefix
, mask
;
163 prefix
= eat_addr(argp
,what
, 0,0, "/",0);
164 sprintf(whatbuf
,"%s length",what
);
165 len
= eat_number(argp
,whatbuf
, 0,32, endchars
,endchar_r
);
167 mask
= (~0UL << (32-len
));
168 if (prefix
& ~mask
) {
169 fprintf(stderr
,"%s prefix %08lx not fully contained in mask %08lx\n",
173 addrnet_mustbein(what
,prefix
,mask
, mprefix
,mmask
);
175 if (mask_r
) *mask_r
= mask
;
176 if (len_r
) *len_r
= len
;
179 int main(int argc
, const char *const *argv
) {
180 static unsigned long gidmaxval
= (unsigned long)((gid_t
)-2);
181 static const char *const protos_ok
[]= { "slip", "cslip", "adaptive", 0 };
183 unsigned long gidmin
, gidmax
, gidadd
;
185 unsigned long routeaddr
, routemask
, tgid
;
186 const char *carg
, *gidlist
;
187 const char *const *cprotop
;
189 char erwhatbuf
[100], erwhatbuf2
[100];
191 if (argc
< NARGS
+1) { fputs("too few arguments\n",stderr
); badusage(); }
192 if (argc
> NARGS
+1) { fputs("too many arguments\n",stderr
); badusage(); }
195 eat_prefixmask(&carg
,"base", 0UL,0UL, 0,0, &baseprefix
, &basemask
, &baselen
);
198 if (!strcmp(carg
,"*")) {
200 if (!*carg
) fatal("no gid authorised");
201 gidmin
= eat_number(&carg
,"gid-min", 0,gidmaxval
, "-",0);
202 gidmax
= eat_number(&carg
,"gid-max", gidmin
,gidmaxval
, ":",0);
203 gidadd
= eat_number(&carg
,"gid-add", 0,gidmaxval
, "/",0);
204 gidlen
= eat_number(&carg
,"gid-len", 0,32-baselen
, 0,0);
206 gidlist
= getenv("USERV_GID");
207 if (!gidlist
) fatal("USERV_GID not set");
209 tgid
= eat_number(&gidlist
,"userv_gid", 0,gidmaxval
, " ",0);
210 if (tgid
>= gidmin
&& tgid
<= gidmax
) goto gid_found
;
215 tgid
&= ((1UL << gidlen
) - 1);
217 baseprefix
|= (tgid
<< (32-baselen
));
218 basemask
= (~0UL << (32-baselen
));
225 localaddr
= eat_addr(&carg
,"local-addr", baseprefix
,basemask
, ",",0);
226 peeraddr
= eat_addr(&carg
,"peer-addr", baseprefix
,basemask
, ",",0);
227 mtu
= eat_number(&carg
,"mtu", 576,65536, ",",0);
229 if (!strcmp(carg
,"debug")) {
232 for (cprotop
= protos_ok
;
233 (proto
= *cprotop
) && strcmp(proto
,carg
);
235 if (!proto
) fatal("invalid protocol");
238 addrnet_mustdiffer("local-addr",localaddr
,~0UL, "peer-addr",peeraddr
,~0UL);
243 carg
++, nexroutes
++) {
244 if (nexroutes
== MAXEXROUTES
) {
245 fprintf(stderr
,"only %d extra routes allowed\n",MAXEXROUTES
);
246 fatal("too many extra routes");
248 sprintf(erwhatbuf
,"route %d",nexroutes
+1);
250 eat_prefixmask(&carg
,erwhatbuf
, baseprefix
,basemask
, ",",0, &routeaddr
,&routemask
,0);
251 addrnet_mustdiffer(erwhatbuf
,routeaddr
,routemask
, "local-addr",localaddr
,~0UL);
252 addrnet_mustdiffer(erwhatbuf
,routeaddr
,routemask
, "peer-addr",peeraddr
,~0UL);
253 for (i
=0; i
<nexroutes
; i
++) {
254 sprintf(erwhatbuf2
,"route %d",i
+1);
255 addrnet_mustdiffer(erwhatbuf
,routeaddr
,routemask
,
256 erwhatbuf2
,exroutes
[i
].prefix
,exroutes
[i
].mask
);
258 exroutes
[nexroutes
].prefix
= routeaddr
;
259 exroutes
[nexroutes
].mask
= routemask
;
260 ip2txt(routeaddr
,exroutes
[nexroutes
].prefixtxt
);
261 ip2txt(routemask
,exroutes
[nexroutes
].masktxt
);
263 ip2txt(localaddr
,localtxt
);
264 ip2txt(peeraddr
,peertxt
);
267 char basetxt
[ATXTLEN
];
269 printf("protocol: debug\n"
270 "base: %08lx/%-2ld == %s/%ld\n"
272 "local: %08lx == %s\n"
273 "peer: %08lx == %s\n"
276 baseprefix
, basemask
, ip2txt(baseprefix
,basetxt
), basemask
,
282 for (i
=0; i
<nexroutes
; i
++) {
283 sprintf(erwhatbuf2
, "route %d:", i
+1);
284 printf("%-9s %08lx/%-2ld == %s/%s\n",
286 exroutes
[i
].prefix
, exroutes
[i
].mask
,
287 exroutes
[i
].prefixtxt
, exroutes
[i
].masktxt
);
289 if (ferror(stdout
) || fclose(stdout
)) sysfatal("flush stdout");