Deleted Added
full compact
nat_cmd.c (47061) nat_cmd.c (47695)
1/*-
2 * The code in this file was written by Eivind Eklund <perhaps@yes.no>,
3 * who places it in the public domain without restriction.
4 *
1/*-
2 * The code in this file was written by Eivind Eklund <perhaps@yes.no>,
3 * who places it in the public domain without restriction.
4 *
5 * $Id: alias_cmd.c,v 1.24 1999/05/08 11:05:59 brian Exp $
5 * $Id: alias_cmd.c,v 1.25 1999/05/12 09:48:39 brian Exp $
6 */
7
8#include <sys/param.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11#include <netdb.h>
12#include <netinet/in_systm.h>
13#include <netinet/in.h>
14#include <netinet/ip.h>
15#include <sys/un.h>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <termios.h>
21
22#ifdef __FreeBSD__
23#include <alias.h>
24#else
25#include "alias.h"
26#endif
27#include "layer.h"
28#include "proto.h"
29#include "defs.h"
30#include "command.h"
31#include "log.h"
32#include "alias_cmd.h"
33#include "descriptor.h"
34#include "prompt.h"
35#include "timer.h"
36#include "fsm.h"
37#include "slcompress.h"
38#include "throughput.h"
39#include "iplist.h"
40#include "mbuf.h"
41#include "lqr.h"
42#include "hdlc.h"
43#include "ipcp.h"
44#include "lcp.h"
45#include "ccp.h"
46#include "link.h"
47#include "mp.h"
48#include "filter.h"
49#ifndef NORADIUS
50#include "radius.h"
51#endif
52#include "bundle.h"
53
54
55static int StrToAddr(const char *, struct in_addr *);
56static int StrToPortRange(const char *, u_short *, u_short *, const char *);
57static int StrToAddrAndPort(const char *, struct in_addr *, u_short *,
58 u_short *, const char *);
59
60
61int
62alias_RedirectPort(struct cmdargs const *arg)
63{
64 if (!arg->bundle->AliasEnabled) {
65 prompt_Printf(arg->prompt, "Alias not enabled\n");
66 return 1;
67 } else if (arg->argc == arg->argn + 3) {
68 char proto_constant;
69 const char *proto;
70 u_short hlocalport;
71 u_short llocalport;
72 u_short haliasport;
73 u_short laliasport;
74 u_short port;
75 int error;
76 struct in_addr local_addr;
77 struct in_addr null_addr;
78 struct alias_link *link;
79
80 proto = arg->argv[arg->argn];
81 if (strcmp(proto, "tcp") == 0) {
82 proto_constant = IPPROTO_TCP;
83 } else if (strcmp(proto, "udp") == 0) {
84 proto_constant = IPPROTO_UDP;
85 } else {
86 prompt_Printf(arg->prompt, "port redirect: protocol must be"
87 " tcp or udp\n");
88 return -1;
89 }
90
91 error = StrToAddrAndPort(arg->argv[arg->argn+1], &local_addr, &llocalport,
92 &hlocalport, proto);
93 if (error) {
94 prompt_Printf(arg->prompt, "alias port: error reading localaddr:port\n");
95 return -1;
96 }
97 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport,
98 proto);
99 if (error) {
100 prompt_Printf(arg->prompt, "alias port: error reading alias port\n");
101 return -1;
102 }
103 null_addr.s_addr = INADDR_ANY;
104
105 if (llocalport > hlocalport) {
106 port = llocalport;
107 llocalport = hlocalport;
108 hlocalport = port;
109 }
110
111 if (laliasport > haliasport) {
112 port = laliasport;
113 laliasport = haliasport;
114 haliasport = port;
115 }
116
117 if (haliasport - laliasport != hlocalport - llocalport) {
118 prompt_Printf(arg->prompt, "alias port: Port ranges must be equal\n");
119 return -1;
120 }
121
122 for (port = laliasport; port <= haliasport; port++) {
123 link = PacketAliasRedirectPort(local_addr,
124 htons(llocalport + (port - laliasport)),
125 null_addr, 0, null_addr, htons(port),
126 proto_constant);
127
128 if (link == NULL) {
129 prompt_Printf(arg->prompt, "alias port: %d: error %d\n", port, error);
130 return 1;
131 }
132 }
133 } else
134 return -1;
135
136 return 0;
137}
138
139
140int
141alias_RedirectAddr(struct cmdargs const *arg)
142{
143 if (!arg->bundle->AliasEnabled) {
144 prompt_Printf(arg->prompt, "alias not enabled\n");
145 return 1;
146 } else if (arg->argc == arg->argn+2) {
147 int error;
148 struct in_addr local_addr;
149 struct in_addr alias_addr;
150 struct alias_link *link;
151
152 error = StrToAddr(arg->argv[arg->argn], &local_addr);
153 if (error) {
154 prompt_Printf(arg->prompt, "address redirect: invalid local address\n");
155 return 1;
156 }
157 error = StrToAddr(arg->argv[arg->argn+1], &alias_addr);
158 if (error) {
159 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n");
160 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name,
161 arg->cmd->syntax);
162 return 1;
163 }
164 link = PacketAliasRedirectAddr(local_addr, alias_addr);
165 if (link == NULL) {
166 prompt_Printf(arg->prompt, "address redirect: packet aliasing"
167 " engine error\n");
168 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name,
169 arg->cmd->syntax);
170 }
171 } else
172 return -1;
173
174 return 0;
175}
176
177
178static int
179StrToAddr(const char *str, struct in_addr *addr)
180{
181 struct hostent *hp;
182
183 if (inet_aton(str, addr))
184 return 0;
185
186 hp = gethostbyname(str);
187 if (!hp) {
188 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
189 return -1;
190 }
191 *addr = *((struct in_addr *) hp->h_addr);
192 return 0;
193}
194
195
196static int
197StrToPort(const char *str, u_short *port, const char *proto)
198{
199 struct servent *sp;
200 char *end;
201
202 *port = strtol(str, &end, 10);
203 if (*end != '\0') {
204 sp = getservbyname(str, proto);
205 if (sp == NULL) {
206 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
207 str, proto);
208 return -1;
209 }
210 *port = ntohs(sp->s_port);
211 }
212
213 return 0;
214}
215
216static int
217StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto)
218{
219 char *minus;
220 int res;
221
222 minus = strchr(str, '-');
223 if (minus)
224 *minus = '\0'; /* Cheat the const-ness ! */
225
226 res = StrToPort(str, low, proto);
227
228 if (minus)
229 *minus = '-'; /* Cheat the const-ness ! */
230
231 if (res == 0) {
232 if (minus)
233 res = StrToPort(minus + 1, high, proto);
234 else
235 *high = *low;
236 }
237
238 return res;
239}
240
241static int
242StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low,
243 u_short *high, const char *proto)
244{
245 char *colon;
246 int res;
247
248 colon = strchr(str, ':');
249 if (!colon) {
250 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
251 return -1;
252 }
253
254 *colon = '\0'; /* Cheat the const-ness ! */
255 res = StrToAddr(str, addr);
256 *colon = ':'; /* Cheat the const-ness ! */
257 if (res != 0)
258 return -1;
259
260 return StrToPortRange(colon + 1, low, high, proto);
261}
262
263int
264alias_ProxyRule(struct cmdargs const *arg)
265{
266 char cmd[LINE_LEN];
267 int f, pos;
268 size_t len;
269
270 if (arg->argn >= arg->argc)
271 return -1;
272
273 for (f = arg->argn, pos = 0; f < arg->argc; f++) {
274 len = strlen(arg->argv[f]);
275 if (sizeof cmd - pos < len + (f ? 1 : 0))
276 break;
277 if (f)
278 cmd[pos++] = ' ';
279 strcpy(cmd + pos, arg->argv[f]);
280 pos += len;
281 }
282
283 return PacketAliasProxyRule(cmd);
284}
285
286int
287alias_Pptp(struct cmdargs const *arg)
288{
289 struct in_addr addr;
290
291 if (arg->argc == arg->argn) {
292 addr.s_addr = INADDR_NONE;
293 PacketAliasPptp(addr);
294 return 0;
295 }
296
297 if (arg->argc != arg->argn + 1)
298 return -1;
299
300 addr = GetIpAddr(arg->argv[arg->argn]);
301 if (addr.s_addr == INADDR_NONE) {
302 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]);
303 return 1;
304 }
305
306 PacketAliasPptp(addr);
307 return 0;
308}
309
310static struct mbuf *
311alias_PadMbuf(struct mbuf *bp, int type)
312{
313 struct mbuf **last;
314 int len;
315
6 */
7
8#include <sys/param.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11#include <netdb.h>
12#include <netinet/in_systm.h>
13#include <netinet/in.h>
14#include <netinet/ip.h>
15#include <sys/un.h>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <termios.h>
21
22#ifdef __FreeBSD__
23#include <alias.h>
24#else
25#include "alias.h"
26#endif
27#include "layer.h"
28#include "proto.h"
29#include "defs.h"
30#include "command.h"
31#include "log.h"
32#include "alias_cmd.h"
33#include "descriptor.h"
34#include "prompt.h"
35#include "timer.h"
36#include "fsm.h"
37#include "slcompress.h"
38#include "throughput.h"
39#include "iplist.h"
40#include "mbuf.h"
41#include "lqr.h"
42#include "hdlc.h"
43#include "ipcp.h"
44#include "lcp.h"
45#include "ccp.h"
46#include "link.h"
47#include "mp.h"
48#include "filter.h"
49#ifndef NORADIUS
50#include "radius.h"
51#endif
52#include "bundle.h"
53
54
55static int StrToAddr(const char *, struct in_addr *);
56static int StrToPortRange(const char *, u_short *, u_short *, const char *);
57static int StrToAddrAndPort(const char *, struct in_addr *, u_short *,
58 u_short *, const char *);
59
60
61int
62alias_RedirectPort(struct cmdargs const *arg)
63{
64 if (!arg->bundle->AliasEnabled) {
65 prompt_Printf(arg->prompt, "Alias not enabled\n");
66 return 1;
67 } else if (arg->argc == arg->argn + 3) {
68 char proto_constant;
69 const char *proto;
70 u_short hlocalport;
71 u_short llocalport;
72 u_short haliasport;
73 u_short laliasport;
74 u_short port;
75 int error;
76 struct in_addr local_addr;
77 struct in_addr null_addr;
78 struct alias_link *link;
79
80 proto = arg->argv[arg->argn];
81 if (strcmp(proto, "tcp") == 0) {
82 proto_constant = IPPROTO_TCP;
83 } else if (strcmp(proto, "udp") == 0) {
84 proto_constant = IPPROTO_UDP;
85 } else {
86 prompt_Printf(arg->prompt, "port redirect: protocol must be"
87 " tcp or udp\n");
88 return -1;
89 }
90
91 error = StrToAddrAndPort(arg->argv[arg->argn+1], &local_addr, &llocalport,
92 &hlocalport, proto);
93 if (error) {
94 prompt_Printf(arg->prompt, "alias port: error reading localaddr:port\n");
95 return -1;
96 }
97 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport,
98 proto);
99 if (error) {
100 prompt_Printf(arg->prompt, "alias port: error reading alias port\n");
101 return -1;
102 }
103 null_addr.s_addr = INADDR_ANY;
104
105 if (llocalport > hlocalport) {
106 port = llocalport;
107 llocalport = hlocalport;
108 hlocalport = port;
109 }
110
111 if (laliasport > haliasport) {
112 port = laliasport;
113 laliasport = haliasport;
114 haliasport = port;
115 }
116
117 if (haliasport - laliasport != hlocalport - llocalport) {
118 prompt_Printf(arg->prompt, "alias port: Port ranges must be equal\n");
119 return -1;
120 }
121
122 for (port = laliasport; port <= haliasport; port++) {
123 link = PacketAliasRedirectPort(local_addr,
124 htons(llocalport + (port - laliasport)),
125 null_addr, 0, null_addr, htons(port),
126 proto_constant);
127
128 if (link == NULL) {
129 prompt_Printf(arg->prompt, "alias port: %d: error %d\n", port, error);
130 return 1;
131 }
132 }
133 } else
134 return -1;
135
136 return 0;
137}
138
139
140int
141alias_RedirectAddr(struct cmdargs const *arg)
142{
143 if (!arg->bundle->AliasEnabled) {
144 prompt_Printf(arg->prompt, "alias not enabled\n");
145 return 1;
146 } else if (arg->argc == arg->argn+2) {
147 int error;
148 struct in_addr local_addr;
149 struct in_addr alias_addr;
150 struct alias_link *link;
151
152 error = StrToAddr(arg->argv[arg->argn], &local_addr);
153 if (error) {
154 prompt_Printf(arg->prompt, "address redirect: invalid local address\n");
155 return 1;
156 }
157 error = StrToAddr(arg->argv[arg->argn+1], &alias_addr);
158 if (error) {
159 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n");
160 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name,
161 arg->cmd->syntax);
162 return 1;
163 }
164 link = PacketAliasRedirectAddr(local_addr, alias_addr);
165 if (link == NULL) {
166 prompt_Printf(arg->prompt, "address redirect: packet aliasing"
167 " engine error\n");
168 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name,
169 arg->cmd->syntax);
170 }
171 } else
172 return -1;
173
174 return 0;
175}
176
177
178static int
179StrToAddr(const char *str, struct in_addr *addr)
180{
181 struct hostent *hp;
182
183 if (inet_aton(str, addr))
184 return 0;
185
186 hp = gethostbyname(str);
187 if (!hp) {
188 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
189 return -1;
190 }
191 *addr = *((struct in_addr *) hp->h_addr);
192 return 0;
193}
194
195
196static int
197StrToPort(const char *str, u_short *port, const char *proto)
198{
199 struct servent *sp;
200 char *end;
201
202 *port = strtol(str, &end, 10);
203 if (*end != '\0') {
204 sp = getservbyname(str, proto);
205 if (sp == NULL) {
206 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
207 str, proto);
208 return -1;
209 }
210 *port = ntohs(sp->s_port);
211 }
212
213 return 0;
214}
215
216static int
217StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto)
218{
219 char *minus;
220 int res;
221
222 minus = strchr(str, '-');
223 if (minus)
224 *minus = '\0'; /* Cheat the const-ness ! */
225
226 res = StrToPort(str, low, proto);
227
228 if (minus)
229 *minus = '-'; /* Cheat the const-ness ! */
230
231 if (res == 0) {
232 if (minus)
233 res = StrToPort(minus + 1, high, proto);
234 else
235 *high = *low;
236 }
237
238 return res;
239}
240
241static int
242StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low,
243 u_short *high, const char *proto)
244{
245 char *colon;
246 int res;
247
248 colon = strchr(str, ':');
249 if (!colon) {
250 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
251 return -1;
252 }
253
254 *colon = '\0'; /* Cheat the const-ness ! */
255 res = StrToAddr(str, addr);
256 *colon = ':'; /* Cheat the const-ness ! */
257 if (res != 0)
258 return -1;
259
260 return StrToPortRange(colon + 1, low, high, proto);
261}
262
263int
264alias_ProxyRule(struct cmdargs const *arg)
265{
266 char cmd[LINE_LEN];
267 int f, pos;
268 size_t len;
269
270 if (arg->argn >= arg->argc)
271 return -1;
272
273 for (f = arg->argn, pos = 0; f < arg->argc; f++) {
274 len = strlen(arg->argv[f]);
275 if (sizeof cmd - pos < len + (f ? 1 : 0))
276 break;
277 if (f)
278 cmd[pos++] = ' ';
279 strcpy(cmd + pos, arg->argv[f]);
280 pos += len;
281 }
282
283 return PacketAliasProxyRule(cmd);
284}
285
286int
287alias_Pptp(struct cmdargs const *arg)
288{
289 struct in_addr addr;
290
291 if (arg->argc == arg->argn) {
292 addr.s_addr = INADDR_NONE;
293 PacketAliasPptp(addr);
294 return 0;
295 }
296
297 if (arg->argc != arg->argn + 1)
298 return -1;
299
300 addr = GetIpAddr(arg->argv[arg->argn]);
301 if (addr.s_addr == INADDR_NONE) {
302 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]);
303 return 1;
304 }
305
306 PacketAliasPptp(addr);
307 return 0;
308}
309
310static struct mbuf *
311alias_PadMbuf(struct mbuf *bp, int type)
312{
313 struct mbuf **last;
314 int len;
315
316 mbuf_SetType(bp, type);
316 for (last = &bp, len = 0; *last != NULL; last = &(*last)->next)
317 len += (*last)->cnt;
318
319 len = MAX_MRU - len;
320 *last = mbuf_Alloc(len, type);
321
322 return bp;
323}
324
325static struct mbuf *
326alias_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp,
327 int pri, u_short *proto)
328{
329 if (!bundle->AliasEnabled || *proto != PROTO_IP)
330 return bp;
331
332 log_Printf(LogDEBUG, "alias_LayerPush: PROTO_IP -> PROTO_IP\n");
317 for (last = &bp, len = 0; *last != NULL; last = &(*last)->next)
318 len += (*last)->cnt;
319
320 len = MAX_MRU - len;
321 *last = mbuf_Alloc(len, type);
322
323 return bp;
324}
325
326static struct mbuf *
327alias_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp,
328 int pri, u_short *proto)
329{
330 if (!bundle->AliasEnabled || *proto != PROTO_IP)
331 return bp;
332
333 log_Printf(LogDEBUG, "alias_LayerPush: PROTO_IP -> PROTO_IP\n");
333 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_IPQ));
334 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_ALIASOUT));
334 PacketAliasOut(MBUF_CTOP(bp), bp->cnt);
335 bp->cnt = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
336
337 return bp;
338}
339
340static struct mbuf *
341alias_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp,
342 u_short *proto)
343{
344 struct ip *pip, *piip;
345 int ret;
346 struct mbuf **last;
347 char *fptr;
348
349 if (!bundle->AliasEnabled || *proto != PROTO_IP)
350 return bp;
351
352 log_Printf(LogDEBUG, "alias_LayerPull: PROTO_IP -> PROTO_IP\n");
335 PacketAliasOut(MBUF_CTOP(bp), bp->cnt);
336 bp->cnt = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
337
338 return bp;
339}
340
341static struct mbuf *
342alias_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp,
343 u_short *proto)
344{
345 struct ip *pip, *piip;
346 int ret;
347 struct mbuf **last;
348 char *fptr;
349
350 if (!bundle->AliasEnabled || *proto != PROTO_IP)
351 return bp;
352
353 log_Printf(LogDEBUG, "alias_LayerPull: PROTO_IP -> PROTO_IP\n");
353 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_IPIN));
354 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_ALIASIN));
354 pip = (struct ip *)MBUF_CTOP(bp);
355 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
356
357 if (pip->ip_p == IPPROTO_IGMP ||
358 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr))))
359 return bp;
360
361 ret = PacketAliasIn(MBUF_CTOP(bp), bp->cnt);
362
363 bp->cnt = ntohs(pip->ip_len);
364 if (bp->cnt > MAX_MRU) {
365 log_Printf(LogWARN, "alias_LayerPull: Problem with IP header length\n");
366 mbuf_Free(bp);
367 return NULL;
368 }
369
370 switch (ret) {
371 case PKT_ALIAS_OK:
372 break;
373
374 case PKT_ALIAS_UNRESOLVED_FRAGMENT:
375 /* Save the data for later */
376 fptr = malloc(bp->cnt);
377 mbuf_Read(bp, fptr, bp->cnt);
378 PacketAliasSaveFragment(fptr);
379 break;
380
381 case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
382 /* Fetch all the saved fragments and chain them on the end of `bp' */
383 last = &bp->pnext;
384 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) {
385 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr);
355 pip = (struct ip *)MBUF_CTOP(bp);
356 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
357
358 if (pip->ip_p == IPPROTO_IGMP ||
359 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr))))
360 return bp;
361
362 ret = PacketAliasIn(MBUF_CTOP(bp), bp->cnt);
363
364 bp->cnt = ntohs(pip->ip_len);
365 if (bp->cnt > MAX_MRU) {
366 log_Printf(LogWARN, "alias_LayerPull: Problem with IP header length\n");
367 mbuf_Free(bp);
368 return NULL;
369 }
370
371 switch (ret) {
372 case PKT_ALIAS_OK:
373 break;
374
375 case PKT_ALIAS_UNRESOLVED_FRAGMENT:
376 /* Save the data for later */
377 fptr = malloc(bp->cnt);
378 mbuf_Read(bp, fptr, bp->cnt);
379 PacketAliasSaveFragment(fptr);
380 break;
381
382 case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
383 /* Fetch all the saved fragments and chain them on the end of `bp' */
384 last = &bp->pnext;
385 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) {
386 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr);
386 *last = mbuf_Alloc(ntohs(((struct ip *)fptr)->ip_len), MB_IPIN);
387 *last = mbuf_Alloc(ntohs(((struct ip *)fptr)->ip_len), MB_ALIASIN);
387 memcpy(MBUF_CTOP(*last), fptr, (*last)->cnt);
388 free(fptr);
389 last = &(*last)->pnext;
390 }
391 break;
392
393 default:
394 mbuf_Free(bp);
395 bp = NULL;
396 break;
397 }
398
399 return bp;
400}
401
402struct layer aliaslayer =
403 { LAYER_ALIAS, "alias", alias_LayerPush, alias_LayerPull };
388 memcpy(MBUF_CTOP(*last), fptr, (*last)->cnt);
389 free(fptr);
390 last = &(*last)->pnext;
391 }
392 break;
393
394 default:
395 mbuf_Free(bp);
396 bp = NULL;
397 break;
398 }
399
400 return bp;
401}
402
403struct layer aliaslayer =
404 { LAYER_ALIAS, "alias", alias_LayerPush, alias_LayerPull };