📄 pfildrv.c
字号:
return 0;}/************************************************************************ * 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. *//* ------------------------------------------------------------------------ *//*ARGSUSED*/static int pfilmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp){ /* LINTED: E_CONSTANT_CONDITION */ PRINT(3,(CE_CONT, "!pfilmodopen(%p,%p,%x,%x,%p) [%s]\n", (void *)q, (void *)devp, oflag, sflag, (void *)crp, QTONM(q))); /* * As per recommendation on man page open(9e) */ 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. *//* ------------------------------------------------------------------------ *//*ARGSUSED*/static int pfilmodclose(queue_t *q, int flag, cred_t *crp){ /* LINTED: E_CONSTANT_CONDITION */ PRINT(3,(CE_CONT, "!pfilmodclose(%p,%x,%p) [%s]\n", (void *)q, flag, (void *)crp, QTONM(q))); qprocsoff(q); qif_delete(q->q_ptr, q); return 0;}/************************************************************************ * other support functions *//* ------------------------------------------------------------------------ *//* 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. *//* ------------------------------------------------------------------------ *//*ARGSUSED*/int pfil_precheck(queue_t *q, mblk_t **mp, int flags, qif_t *qif){ register struct ip *ip; size_t hlen, len, off, mlen, iphlen, plen; packet_filter_hook_t *pfh; qpktinfo_t qpkt, *qpi; struct pfil_head *ph; mblk_t *m, *mt = *mp; int err, out, sap; u_char *bp;#if SOLARIS2 >= 8 ip6_t *ip6;#endif#ifndef sparc u_short __ipoff, __iplen;#endif 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. */ out = (flags & PFIL_OUT) ? 1 : 0; off = (out) ? qpi->qpi_hl : 0; ip = NULL; m = NULL; /* * 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 { atomic_add_long(&qif->qf_notdata, 1); return -1; } } else { m = mt->b_cont; if (m == NULL) { atomic_add_long(&qif->qf_nodata, 1); return -3; /* No data blocks */ } } break; } case M_DATA : m = mt; break; default : atomic_add_long(&qif->qf_notdata, 1); 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) { atomic_add_long(&qif->qf_nodata, 1); return -3; /* No data blocks */ } /* * This is a complete kludge to try and work around some bizarre * packets which drop through into pfil_donotip. */ if ((mt != m) && (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO)) { dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp; if ((dl->dl_primitive == DL_UNITDATA_IND) && (dl->dl_group_address == 1)) { qpi->qpi_flags |= QF_GROUP; if (((*((u_char *)m->b_rptr) == 0x0) && ((*((u_char *)m->b_rptr + 2) == 0x45)))) off += 2; } } /* * We might have a 1st data block which is really M_PROTO, i.e. it is * only big enough for the link layer header */ while ((len = m->b_wptr - m->b_rptr) <= off) { off -= len; m = m->b_cont; if (m == NULL) { atomic_add_long(&qif->qf_nodata, 1); return -4; /* not enough data for IP */ } } ip = (struct ip *)(m->b_rptr + off); len = m->b_wptr - m->b_rptr - off; mlen = msgdsize(m); sap = qif->qf_sap; if (mlen == 0) mlen = m->b_wptr - m->b_rptr; mlen -= off;#ifdef PFILDEBUG /*LINTED: E_CONSTANT_CONDITION*/ PRINT(10,(CE_CONT, "!IP Filter[%s]: out %d len %ld/%ld sap %d ip %p b_rptr %p off %ld m %p/%d/%ld/%p mt %p/%d/%ld/%p\n", qif->qf_name, out, len, mlen, sap, (void *)ip, (void *)m->b_rptr, off, (void *)m, MTYPE(m), MLEN(m), (void *)m->b_cont, (void *)mt, MTYPE(mt), MLEN(mt), (void *)mt->b_cont));#endif /* * If there is more than one copy of this message traversing the * STREAMS stack (ie the packet is being used for snoop data), the * IP header isn't on a 32bit aligned address, or the IP header * isn't contain within a single block, then make a copy which * meets our requirements and do a freemsg on the one passed in * since we're no longer using it or passing it up. */ if ((pfil_delayed_copy == 0 && m->b_datap->db_ref > 1) || ((u_int)ip & 0x3) || len < sizeof(*ip) || (sap != ETHERTYPE_IP#if SOLARIS2 >= 8 && sap != IP6_DL_SAP#endif )) { mblk_t *b; mblk_t *nm; mblk_t *nmt; mblk_t *previous_nm;forced_copy: nmt = NULL; previous_nm = NULL; /* * Duplicate the message block descriptors up to (and * including if the offset is non-zero) the block where * IP begins. */ for (b = mt; b != m || off; b = b->b_cont) { nm = dupb(b); if (nm == NULL) { atomic_add_long(&qif->qf_copyfail, 1); if (nmt) freemsg(nmt); return ENOBUFS; } nm->b_cont = NULL; if (nmt) linkb(previous_nm, nm); else nmt = nm; previous_nm = nm; /* * Set the length so the block only contains what * appears before IP. */ if (b == m) { nm->b_wptr = nm->b_rptr + off; break; } } m->b_rptr += off; nm = msgpullup(m, -1); m->b_rptr -= off; if (nm == NULL) { atomic_add_long(&qif->qf_copyfail, 1); if (nmt) freemsg(nmt); return ENOBUFS; } if (nmt) linkb(previous_nm, nm); else nmt = nm; freemsg(mt); *mp = nmt; mt = nmt; m = nm; ip = (struct ip *)m->b_rptr; len = m->b_wptr - m->b_rptr; mlen = len; off = 0; } if (sap == ETHERTYPE_IP) { u_short tlen; hlen = sizeof(*ip); /* XXX - might not be aligned (from ppp?) */ ((char *)&tlen)[0] = ((char *)&ip->ip_len)[0]; ((char *)&tlen)[1] = ((char *)&ip->ip_len)[1]; plen = ntohs(tlen); ph = &pfh_inet4; }#if SOLARIS2 >= 8 else if (sap == IP6_DL_SAP) { u_short tlen; hlen = sizeof(ip6_t); ip6 = (ip6_t *)ip; /* XXX - might not be aligned (from ppp?) */ ((char *)&tlen)[0] = ((char *)&ip6->ip6_plen)[0]; ((char *)&tlen)[1] = ((char *)&ip6->ip6_plen)[1]; plen = ntohs(tlen); if (plen == 0) return EMSGSIZE; /* Jumbo gram */ ph = &pfh_inet6; }#endif else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -