📄 pfildrv.c
字号:
/* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */struct uio;#include <sys/conf.h>#include <sys/stream.h>#include <sys/errno.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/cmn_err.h>#include <sys/dlpi.h>#include <sys/io.h>#include <sys/moddefs.h>#include <net/if.h>#include <netinet/if_ether.h>#include <net/mtcp.h>#include <netinet/in_systm.h>#include <netinet/in.h>#undef IPOPT_EOL#undef IPOPT_NOP#undef IPOPT_RR#undef IPOPT_LSRR#undef IPOPT_SSRR#include <netinet/ip.h>#ifdef ETHERTYPE_IPV6# include <netinet/ip6.h>#endif#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/ip_icmp.h>#include "compat.h"#include "qif.h"#include "pfil.h"#undef USE_SERVICE_ROUTINE#define MINSDUSZ 1#define MAXSDUSZ INFPSZkrwlock_t pfil_rw;/****************************************************************************//* pfil Streams Module Definition */#define PFIL_NAME "pfil"static int pfilmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp);static int pfilmodclose(queue_t *q, int flag, cred_t *crp);static struct module_info pfil_info = { 5051, "pfil driver module "/**/PFIL_RELEASE, 0, 65535, 65536, 1};static struct qinit pfilmod_rinit = { (pfi_t)pfilmodrput, NULL, pfilmodopen, pfilmodclose, NULL, &pfil_info, NULL};static struct qinit pfilmod_winit = { (pfi_t)pfilmodwput, NULL, NULL, NULL, NULL, &pfil_info, NULL};struct streamtab pfilmodinfo = { &pfilmod_rinit, &pfilmod_winit, NULL, NULL};static streams_info_t pfil_str_info = { PFIL_NAME, /* name */ -1, /* major number */ { NULL, NULL, NULL, NULL }, /* streamtab */ STR_IS_MODULE | MGR_IS_MP | /* streams flags */ STR_SYSV4_OPEN | STR_MP_OPEN_CLOSE, SQLVL_QUEUE, /* sync level */ "", /* elsewhere sync name */};/* End of pfil Streams Module initialization *//**********************************************************************//* DLKM specific structures for the pfil Streams Module */extern struct mod_operations str_mod_ops;extern struct mod_conf_data pfil_conf_data;static int pfil_load __P((void *));static int pfil_unload __P((void *));static struct mod_type_data pfil_drv_link = { "pfilm STREAMS module "/**/PFIL_RELEASE, &pfil_str_info };static struct modlink pfil_mod_link[] = { { &str_mod_ops, (void *)&pfil_drv_link }, { NULL, (void *)NULL }};struct modwrapper pfil_wrapper = { MODREV, pfil_load, pfil_unload, (void (*)())NULL, (void *)&pfil_conf_data, (struct modlink*)&pfil_mod_link};/************************************************************************ * STREAMS module functions *//* ------------------------------------------------------------------------ *//* Function: pfilmodopen *//* Returns: int - 0 == success, else error *//* Parameters: q(I) - pointer to read-side STREAMS queue *//* devp(I) - pointer to a device number *//* oflag(I) - file status open flags (always 0 for module open)*//* sflag(I) - flag indicating how the open is being made *//* crp(I) - pointer to message credentials from the user *//* *//* open() entry hook for the STREAMS module. *//* ------------------------------------------------------------------------ */static int pfilmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp){ PRINT(3,(CE_CONT, "pfilmodopen(%lx,%lx,%x,%x,%lx) [%s]\n", q, devp, flag, sflag, crp, QTONM(q))); if (sflag != MODOPEN) return ENXIO; q->q_ptr = qif_new(q, KM_SLEEP); WR(q)->q_ptr = q->q_ptr; qprocson(q); return 0;}/* ------------------------------------------------------------------------ *//* Function: pfilmodclose *//* Returns: int - always returns 0. *//* Parameters: q(I) - pointer to read-side STREAMS queue *//* flag(I) - file status flag *//* crp(I) - pointer to message credentials from the user *//* *//* close() entry hook for the STREAMS module. qif_delete() takes care of *//* setting q_ptr back to NULL for both this and the write side queue. *//* ------------------------------------------------------------------------ */static int pfilmodclose(queue_t *q, int flag, cred_t *crp){ PRINT(3,(CE_CONT, "pfilmodclose(%lx,%x,%lx) [%s]\n", q, flag, crp, QTONM(q))); qprocsoff(q); qif_delete(q->q_ptr, q); return 0;}/* ------------------------------------------------------------------------ *//* Function: pfil_precheck *//* Returns: int - < 0 pass packet because it's not a type subject to *//* firewall rules (i.e. internal STREAMS messages), *//* 0 == pass packet, else > 0 indicates passing *//* prohibited (possibly due to an error occuring in *//* this function.) *//* Parameters: q(I) - pointer to STREAMS queue *//* mp(I) - pointer to STREAMS message *//* qif(I) - pointer to per-queue interface information *//* Locks: pfil_rw *//* *//* In here we attempt to determine if there is an IP packet within an mblk *//* that is being passed along and if there is, ensure that it falls on a 32 *//* bit aligned address and at least all of the layer 3 header is in one *//* buffer, preferably all the layer 4 too if we recognise it. Finally, if *//* we can be sure that the buffer passes some sanity checks, pass it on to *//* the registered callbacks for the particular protocol/direction. *//* ------------------------------------------------------------------------ */int pfil_precheck(queue_t *q, mblk_t **mp, int flags, qif_t *qif){ register struct ip *ip;#ifdef ETHERTYPE_IPV6 register ip6_t *ip6;#endif size_t hlen, len, off, mlen, iphlen, plen, p; int err, out, sap, realigned = 0; packet_filter_hook_t *pfh; qpktinfo_t qpkt, *qpi; struct pfil_head *ph; mblk_t *m, *mt = *mp; struct tcphdr *tcp; u_char *bp, *s; int cko = 0; mblk_t *mi = *mp; qpi = &qpkt; qpi->qpi_q = q; qpi->qpi_off = 0; qpi->qpi_name = qif->qf_name; qpi->qpi_real = qif; qpi->qpi_ill = qif->qf_ill; qpi->qpi_hl = qif->qf_hl; qpi->qpi_ppa = qif->qf_ppa; qpi->qpi_num = qif->qf_num; qpi->qpi_flags = qif->qf_flags; qpi->qpi_max_frag = qif->qf_max_frag; if ((flags & PFIL_GROUP) != 0) qpi->qpi_flags |= QF_GROUP; /* * If there is only M_DATA for a packet going out, then any header * information (which would otherwise appear in an M_PROTO mblk before * the M_DATA) is prepended before the IP header. We need to set the * offset to account for this. - see MMM */ out = (flags & PFIL_OUT) ? 1 : 0; cko = (mt->b_flag & MSGCKO); if (out != 0) { /* * If outbound, set offset to qif->qf_hl as it will include * the cko length if cko is present. */ off = qpi->qpi_hl; } else { /* * unlike before,in the IN path, we need to set the offset * as there maybe cko information we need to take care of. * If inbound, then the offset is: * 0 in nonfastpath/no cko * 8 in cko */ if (cko) off = 8; else off = 0; }tryagain: ip = NULL; m = NULL; cko = (mt->b_flag & MSGCKO); PRINT(9,(CE_CONT, "pfil_precheck(%lx,%lx,%x,%lx) sz %d %d hl %d\n", q, mp, flags, qif, mt->b_wptr - mt->b_rptr, msgdsize(mt), qif->qf_hl)); /* * If the message protocol block indicates that there isn't a data * block following it, just return back. */ bp = (u_char *)ALIGN32(mt->b_rptr); switch (MTYPE(mt)) { case M_PROTO : case M_PCPROTO : { dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp; if ((dl->dl_primitive != DL_UNITDATA_IND) && (dl->dl_primitive != DL_UNITDATA_REQ)) { ip = (struct ip *)dl; if ((ip->ip_v == IPVERSION) && (ip->ip_hl == (sizeof(*ip) >> 2)) && (ntohs(ip->ip_len) == mt->b_wptr - mt->b_rptr)) { off = 0; m = mt; } else { qif->qf_notdata++; return -1; } } else { m = mt->b_cont; if (m == NULL) { qif->qf_notdata++; return -3; /* No data blocks */ } } break; } case M_DATA : m = mt; break; default : qif->qf_notdata++; return -2; } /* * Find the first data block, count the data blocks in this chain and * the total amount of data. */ if (ip == NULL) for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont) off = 0; /* Any non-M_DATA cancels the offset */ if (m == NULL) { qif->qf_nodata++; return -3; /* No data blocks */ } /* * This is a complete kludge to try and work around some bizarre * packets which drop through into fr_donotip. */ if ((mt != m) && (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO)) { dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -