summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/fil.c90
-rw-r--r--sys/netinet/ip_fil.c19
-rw-r--r--sys/netinet/ip_fil_compat.h10
-rw-r--r--sys/netinet/ip_nat.c32
-rw-r--r--sys/netinet/ip_nat.h9
-rw-r--r--sys/netinet/ip_state.c30
-rw-r--r--sys/netinet/ip_state.h8
7 files changed, 111 insertions, 87 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c
index f102fd8eaa5..8bbb4f70aad 100644
--- a/sys/netinet/fil.c
+++ b/sys/netinet/fil.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fil.c,v 1.9 1997/04/03 15:46:36 kstailey Exp $ */
+/* $OpenBSD: fil.c,v 1.10 1997/06/23 19:03:47 kstailey Exp $ */
/*
* (C)opyright 1993-1996 by Darren Reed.
*
@@ -9,7 +9,7 @@
#if 0
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "Id: fil.c,v 2.0.1.3 1997/01/29 13:38:54 darrenr Exp";
+static char rcsid[] = "$DRId: fil.c,v 2.0.1.10 1997/04/13 22:33:07 darrenr Exp $";
#endif
#endif
@@ -103,10 +103,19 @@ extern int ipllog __P((u_int, ip_t *, register fr_info_t *,
# endif
#endif
+#ifndef IPF_LOGGING
+#define IPF_LOGGING 0
+#endif
+#ifdef IPF_DEFAULT_PASS
+#define IPF_NOMATCH (IPF_DEFAULT_PASS|FR_NOMATCH)
+#else
+#define IPF_NOMATCH (FR_PASS|FR_NOMATCH)
+#endif
+
struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
*ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
-int fr_flags = 0, fr_active = 0;
+int fr_flags = IPF_LOGGING, fr_active = 0;
fr_info_t frcache[2];
@@ -446,8 +455,8 @@ fr_scanlist(pass, ip, fin, m)
if (portcmp) {
if (!fr_tcpudpchk(fr, fin))
continue;
- } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
- fr->fr_tcpfm)
+ } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
+ fr->fr_tcpfm)
continue;
} else if (fi->fi_p == IPPROTO_ICMP) {
if (!off && (fin->fin_dlen > 1)) {
@@ -586,16 +595,12 @@ fr_check(ip, hlen, ifp, out
frstats[out].fr_chit++;
pass = fin->fin_fr->fr_flags;
} else {
- pass = FR_NOMATCH;
+ pass = IPF_NOMATCH;
if ((fin->fin_fr = ipfilter[out][fr_active]))
- pass = FR_SCANLIST(FR_NOMATCH, ip, fin, m);
+ pass = FR_SCANLIST(IPF_NOMATCH, ip, fin, m);
bcopy((char *)fin, (char *)fc, FI_CSIZE);
- if (pass & FR_NOMATCH) {
+ if (pass & FR_NOMATCH)
frstats[out].fr_nom++;
-#ifdef NOMATCH
- pass |= NOMATCH;
-#endif
- }
}
fr = fin->fin_fr;
@@ -616,7 +621,7 @@ fr_check(ip, hlen, ifp, out
}
}
- if (fr && fr->fr_func)
+ if (fr && fr->fr_func && !(pass & FR_CALLNOW))
pass = (*fr->fr_func)(pass, ip, fin);
if (out) {
@@ -657,6 +662,14 @@ logit:
}
#endif /* IPFILTER_LOG */
+#ifdef _KERNEL
+ if (fr && (pass & FR_DUP))
+# if SOLARIS
+ mc = dupmsg(m);
+# else
+ mc = m_copy(m, 0, M_COPYALL);
+# endif
+#endif
if (pass & FR_PASS)
frstats[out].fr_pass++;
else if (pass & FR_BLOCK) {
@@ -664,39 +677,43 @@ logit:
/*
* Should we return an ICMP packet to indicate error
* status passing through the packet filter ?
+ * WARNING: ICMP error packets AND TCP RST packets should
+ * ONLY be sent in repsonse to incoming packets. Sending them
+ * in response to outbound packets can result in a panic on
+ * some operating systems.
*/
+ if (!out) {
#ifdef _KERNEL
- if (pass & FR_RETICMP) {
+ if (pass & FR_RETICMP) {
# if SOLARIS
- ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
- qif, ip->ip_src);
+ ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
+ qif, ip->ip_src);
# else
- ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
- ifp, ip->ip_src);
- m = NULL; /* freed by icmp_error() */
+ ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
+ ifp, ip->ip_src);
+ m = *mp = NULL; /* freed by icmp_error() */
# endif
- frstats[0].fr_ret++;
- } else if ((pass & FR_RETRST) &&
- !(fin->fin_fi.fi_fl & FI_SHORT)) {
- if (SEND_RESET(ip, qif, q) == 0)
- frstats[1].fr_ret++;
- }
+ frstats[0].fr_ret++;
+ } else if ((pass & FR_RETRST) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ if (SEND_RESET(ip, qif, q) == 0)
+ frstats[1].fr_ret++;
+ }
#else
- if (pass & FR_RETICMP) {
- verbose("- ICMP unreachable sent\n");
- frstats[0].fr_ret++;
- } else if ((pass & FR_RETRST) &&
- !(fin->fin_fi.fi_fl & FI_SHORT)) {
- verbose("- TCP RST sent\n");
- frstats[1].fr_ret++;
- }
+ if (pass & FR_RETICMP) {
+ verbose("- ICMP unreachable sent\n");
+ frstats[0].fr_ret++;
+ } else if ((pass & FR_RETRST) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ verbose("- TCP RST sent\n");
+ frstats[1].fr_ret++;
+ }
#endif
+ }
}
#ifdef _KERNEL
# if !SOLARIS
- if (pass & FR_DUP)
- mc = m_copy(m, 0, M_COPYALL);
if (fr) {
frdest_t *fdp = &fr->fr_tif;
@@ -704,7 +721,6 @@ logit:
(fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
ipfr_fastroute(m, fin, fdp);
m = *mp = NULL;
- pass = 0;
}
if (mc)
ipfr_fastroute(mc, fin, &fr->fr_dif);
@@ -713,8 +729,6 @@ logit:
m_freem(m);
return (pass & FR_PASS) ? 0 : -1;
# else
- if (pass & FR_DUP)
- mc = dupmsg(m);
if (fr) {
frdest_t *fdp = &fr->fr_tif;
diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c
index fa96d88a55f..1de368d9bfe 100644
--- a/sys/netinet/ip_fil.c
+++ b/sys/netinet/ip_fil.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_fil.c,v 1.13 1997/04/18 06:10:08 niklas Exp $ */
+/* $OpenBSD: ip_fil.c,v 1.14 1997/06/23 19:03:48 kstailey Exp $ */
/*
* (C)opyright 1993,1994,1995 by Darren Reed.
*
@@ -8,7 +8,7 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "Id: ip_fil.c,v 2.0.1.5 1997/01/29 13:41:45 darrenr Exp ";
+static char rcsid[] = "$DRId: ip_fil.c,v 2.0.1.8 1997/03/20 15:51:56 darrenr Exp $";
#endif
#include <sys/param.h>
@@ -412,16 +412,13 @@ frrequest(req, data, set)
{
register frentry_t *fp, *f, **fprev;
register frentry_t **ftail;
- frentry_t fr;
+ frentry_t frd;
frdest_t *fdp;
- struct frentry frd;
int error = 0, in;
- fp = &fr;
+ fp = &frd;
IRCOPY(data, (caddr_t)fp, sizeof(*fp));
- bzero((char *)frcache, sizeof(frcache[0]) * 2);
-
in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
if (fp->fr_flags & FR_ACCOUNT) {
ftail = fprev = &ipacct[in][set];
@@ -430,8 +427,8 @@ frrequest(req, data, set)
else
return ESRCH;
- IRCOPY((char *)fp, (char *)&frd, sizeof(frd));
- fp = &frd;
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
if (*fp->fr_ifname) {
fp->fr_ifa = GETUNIT(fp->fr_ifname);
if (!fp->fr_ifa)
@@ -755,7 +752,11 @@ send_reset(ti)
#ifndef IPFILTER_LKM
+# if BSD < 199306
+int
+# else
void
+# endif
iplinit()
{
/* (void) ipl_enable(); must explicitly enable with ipf -E */
diff --git a/sys/netinet/ip_fil_compat.h b/sys/netinet/ip_fil_compat.h
index 231047e09ee..92f5189541d 100644
--- a/sys/netinet/ip_fil_compat.h
+++ b/sys/netinet/ip_fil_compat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_fil_compat.h,v 1.5 1997/02/13 05:54:16 kstailey Exp $ */
+/* $OpenBSD: ip_fil_compat.h,v 1.6 1997/06/23 19:03:49 kstailey Exp $ */
/*
* (C)opyright 1993, 1994, 1995 by Darren Reed.
*
@@ -7,16 +7,12 @@
* to the original author and the contributors.
*
* @(#)ip_compat.h 1.8 1/14/96
- * Id: ip_compat.h,v 2.0.1.4 1997/02/04 14:24:25 darrenr Exp
+ * $DRId: ip_compat.h,v 2.0.1.4 1997/02/04 14:24:25 darrenr Exp $
*/
#ifndef __IP_FIL_COMPAT_H_
#define __IP_FIL_COMPAT_H__
-#ifdef _KERNEL /* XXX */
-#define IPFILTER_LOG
-#endif /* _KERNEL */
-
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#endif
@@ -188,7 +184,7 @@ extern vm_map_t kmem_map;
# define UIOMOVE(a,b,c,d) uiomove(a,b,d)
# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0)
# endif /* BSD */
-# if (defined(NetBSD1_0) && (NetBSD1_0 > 1))
+# if defined(NetBSD1_0) && (NetBSD1_0 > 1)
# define SPLNET(x) x = splsoftnet()
# else
# if !SOLARIS
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
index a2ce5a9e12b..eeb23ec49f2 100644
--- a/sys/netinet/ip_nat.c
+++ b/sys/netinet/ip_nat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_nat.c,v 1.11 1997/04/18 06:10:07 niklas Exp $ */
+/* $OpenBSD: ip_nat.c,v 1.12 1997/06/23 19:03:49 kstailey Exp $ */
/*
* (C)opyright 1995-1996 by Darren Reed.
*
@@ -12,7 +12,7 @@
#if 0
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static char rcsid[] = "Id: ip_nat.c,v 2.0.1.10 1997/02/08 06:38:49 darrenr Exp";
+static char rcsid[] = "$DRId: ip_nat.c,v 2.0.1.14 1997/04/22 12:47:39 darrenr Exp $";
#endif
#endif
@@ -170,15 +170,18 @@ nat_ioctl(data, cmd, mode)
{
register ipnat_t *nat, *n = NULL, **np = NULL;
ipnat_t natd;
- int error = 0, ret;
+ int error = 0, ret, s;
/*
* For add/delete, look to see if the NAT entry is already present
*/
MUTEX_ENTER(&ipf_nat);
+ SPLNET(s);
if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
IRCOPY(data, (char *)&natd, sizeof(natd));
nat = &natd;
+ nat->in_inip &= nat->in_inmsk;
+ nat->in_outip &= nat->in_outmsk;
for (np = &nat_list; (n = *np); np = &n->in_next)
if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
IPN_CMPSIZ))
@@ -200,7 +203,7 @@ nat_ioctl(data, cmd, mode)
error = ENOMEM;
break;
}
- IRCOPY((char *)data, (char *)n, sizeof(*n));
+ bcopy((char *)nat, (char *)n, sizeof(*n));
n->in_ifp = (void *)GETUNIT(n->in_ifname);
n->in_next = *np;
n->in_use = 0;
@@ -275,6 +278,7 @@ nat_ioctl(data, cmd, mode)
IWCOPY((caddr_t)&ret, data, sizeof(ret));
break;
}
+ SPLX(s);
MUTEX_EXIT(&ipf_nat);
return error;
}
@@ -409,6 +413,7 @@ nat_new(np, ip, fin, flags, direction)
return NULL;
bzero((char *)nat, sizeof(*nat));
+ nat->nat_flags = flags;
/*
* Search the current table for a match.
@@ -574,8 +579,9 @@ nat_inlookup(flags, src, sport, mapdst, mapdport)
for (; nat; nat = nat->nat_hnext[1])
if (nat->nat_oip.s_addr == src.s_addr &&
nat->nat_outip.s_addr == mapdst.s_addr &&
- (!flags || (nat->nat_oport == sport &&
- nat->nat_outport == mapdport)))
+ flags == nat->nat_flags && (!flags ||
+ (nat->nat_oport == sport &&
+ nat->nat_outport == mapdport)))
return nat;
return NULL;
}
@@ -601,8 +607,8 @@ nat_outlookup(flags, src, sport, dst, dport)
for (; nat; nat = nat->nat_hnext[0])
if (nat->nat_inip.s_addr == src.s_addr &&
nat->nat_oip.s_addr == dst.s_addr &&
- (!flags || (nat->nat_inport == sport &&
- nat->nat_oport == dport)))
+ (!flags || flags & nat->nat_flags) && (!flags ||
+ (nat->nat_inport == sport && nat->nat_oport == dport)))
return nat;
return NULL;
}
@@ -627,8 +633,9 @@ nat_lookupmapip(flags, mapsrc, mapsport, dst, dport)
for (; nat; nat = nat->nat_hnext[0])
if (nat->nat_outip.s_addr == mapsrc.s_addr &&
nat->nat_oip.s_addr == dst.s_addr &&
- (!flags || (nat->nat_outport == mapsport &&
- nat->nat_oport == dport)))
+ flags == nat->nat_flags && (!flags ||
+ (nat->nat_outport == mapsport &&
+ nat->nat_oport == dport)))
return nat;
return NULL;
}
@@ -884,12 +891,13 @@ ip_natin(ip, hlen, fin)
void
ip_natunload()
{
+ int s;
MUTEX_ENTER(&ipf_nat);
-
+ SPLNET(s);
(void) clear_natlist();
(void) flush_nattable();
-
+ SPLX(s)
MUTEX_EXIT(&ipf_nat);
}
diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h
index 6de60c460f8..d8a2a18bd51 100644
--- a/sys/netinet/ip_nat.h
+++ b/sys/netinet/ip_nat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_nat.h,v 1.6 1997/04/18 06:10:07 niklas Exp $ */
+/* $OpenBSD: ip_nat.h,v 1.7 1997/06/23 19:03:50 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
@@ -7,7 +7,7 @@
* to the original author and the contributors.
*
* @(#)ip_nat.h 1.5 2/4/96
- * Id: ip_nat.h,v 2.0.1.7 1997/01/30 12:39:41 darrenr Exp
+ * $DRId: ip_nat.h,v 2.0.1.9 1997/03/20 10:20:50 darrenr Exp $
*/
#ifndef __IP_NAT_H_
@@ -41,7 +41,8 @@
#define NAT_SIZE 367
typedef struct nat {
- int nat_age;
+ u_long nat_age;
+ int nat_flags;
u_long nat_sumd;
u_long nat_ipsumd;
struct in_addr nat_inip;
@@ -88,7 +89,7 @@ typedef struct ipnat {
#define NAT_REDIRECT 1
#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \
- sizeof(int))
+ sizeof(int) + IFNAMSIZ)
typedef struct natlookup {
struct in_addr nl_inip;
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c
index a2f23142917..469129165f2 100644
--- a/sys/netinet/ip_state.c
+++ b/sys/netinet/ip_state.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_state.c,v 1.8 1997/06/09 15:50:57 kstailey Exp $ */
+/* $OpenBSD: ip_state.c,v 1.9 1997/06/23 19:03:51 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
@@ -9,7 +9,7 @@
#if 0
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "Id: ip_state.c,v 2.0.1.2 1997/01/09 15:22:45 darrenr Exp ";
+static char rcsid[] = "$DRId: ip_state.c,v 2.0.1.5 1997/04/13 22:29:18 darrenr Exp $";
#endif
#endif
@@ -58,7 +58,6 @@ static char rcsid[] = "Id: ip_state.c,v 2.0.1.2 1997/01/09 15:22:45 darrenr Exp
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
-void set_tcp_age __P((int *, u_char *, ip_t *, fr_info_t *, int));
#ifndef _KERNEL
int fr_tcpstate __P((register ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *,
u_short, ipstate_t **));
@@ -246,10 +245,9 @@ fr_tcpstate(is, fin, ip, tcp, sport
*/
seq = ntohl(tcp->th_seq);
ack = ntohl(tcp->th_ack);
-
source = (sport == is->is_sport);
- if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */
+ if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */
ack = source ? is->is_ack : is->is_seq;
if (source) {
@@ -321,7 +319,7 @@ fr_checkstate(ip, fin)
register u_char pr;
struct icmp *ic;
tcphdr_t *tcp;
- u_int hv, hlen;
+ u_int hv, hlen, pass;
if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
return 0;
@@ -357,8 +355,9 @@ fr_checkstate(ip, fin)
continue;
is->is_age = fr_icmptimeout;
ips_stats.iss_hits++;
+ pass = is->is_pass;
MUTEX_EXIT(&ipf_state);
- return is->is_pass;
+ return pass;
}
MUTEX_EXIT(&ipf_state);
break;
@@ -379,19 +378,17 @@ fr_checkstate(ip, fin)
, NULL
#endif
)) {
+ pass = is->is_pass;
#ifdef _KERNEL
MUTEX_EXIT(&ipf_state);
- return is->is_pass;
#else
- int pass = is->is_pass;
-
if (tcp->th_flags & TCP_CLOSE) {
*isp = is->is_next;
isp = &ips_table[hv];
KFREE(is);
}
- return pass;
#endif
+ return pass;
}
}
MUTEX_EXIT(&ipf_state);
@@ -414,8 +411,9 @@ fr_checkstate(ip, fin)
IPPAIR(src, dst, is->is_src, is->is_dst)) {
ips_stats.iss_hits++;
is->is_age = fr_udptimeout;
+ pass = is->is_pass;
MUTEX_EXIT(&ipf_state);
- return is->is_pass;
+ return pass;
}
MUTEX_EXIT(&ipf_state);
break;
@@ -436,13 +434,16 @@ fr_stateunload()
{
register int i;
register ipstate_t *is, **isp;
+ int s;
MUTEX_ENTER(&ipf_state);
+ SPLNET(s);
for (i = 0; i < IPSTATE_SIZE; i++)
for (isp = &ips_table[i]; (is = *isp); ) {
*isp = is->is_next;
KFREE(is);
}
+ SPLX(s);
MUTEX_EXIT(&ipf_state);
}
@@ -456,8 +457,10 @@ fr_timeoutstate()
{
register int i;
register ipstate_t *is, **isp;
+ int s;
MUTEX_ENTER(&ipf_state);
+ SPLNET(s);
for (i = 0; i < IPSTATE_SIZE; i++)
for (isp = &ips_table[i]; (is = *isp); )
if (is->is_age && !--is->is_age) {
@@ -470,6 +473,7 @@ fr_timeoutstate()
ips_num--;
} else
isp = &is->is_next;
+ SPLX(s);
MUTEX_EXIT(&ipf_state);
}
@@ -480,7 +484,7 @@ fr_timeoutstate()
*/
void
set_tcp_age(age, state, ip, fin, dir)
- int *age;
+ long *age;
u_char *state;
ip_t *ip;
fr_info_t *fin;
diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h
index f51dc51f67c..09c730cda9e 100644
--- a/sys/netinet/ip_state.h
+++ b/sys/netinet/ip_state.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_state.h,v 1.4 1997/02/11 22:23:30 kstailey Exp $ */
+/* $OpenBSD: ip_state.h,v 1.5 1997/06/23 19:03:51 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
@@ -7,7 +7,7 @@
* to the original author and the contributors.
*
* @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed
- * Id: ip_state.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp
+ * $DRId: ip_state.h,v 2.0.1.2 1997/03/20 10:20:53 darrenr Exp $
*/
#ifndef __IP_STATE_H__
#define __IP_STATE_H__
@@ -38,7 +38,7 @@ typedef struct tcpstate {
typedef struct ipstate {
struct ipstate *is_next;
- int is_age;
+ u_long is_age;
u_int is_pass;
struct in_addr is_src;
struct in_addr is_dst;
@@ -82,7 +82,7 @@ extern ips_stat_t *fr_statetstats __P((void));
extern int fr_addstate __P((ip_t *, fr_info_t *, u_int));
extern int fr_checkstate __P((ip_t *, fr_info_t *));
extern void fr_timeoutstate __P((void));
-extern void set_tcp_age __P((int *, u_char *, ip_t *, fr_info_t *, int));
+extern void set_tcp_age __P((long *, u_char *, ip_t *, fr_info_t *, int));
# ifdef _KERNEL
extern void fr_stateunload __P((void));
# endif