⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qif.c

📁 pfil src. solaris, freebsd
💻 C
字号:
/* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */struct uio;#include <sys/systm.h>#include <sys/types.h>#include <sys/param.h>#include <sys/errno.h>#include <sys/uio.h>#include <sys/buf.h>#include <sys/cmn_err.h>#include <sys/stat.h>#include <sys/spinlock.h>#include <sys/lock.h>#include <sys/stream.h>#include <sys/poll.h>#include <sys/byteorder.h>#include <sys/socket.h>#include <sys/dlpi.h>#include <sys/stropts.h>#include <net/if.h>#include "../netinet/ip_info.h"#include "compat.h"#include "qif.h"#include "pfil.h"static kmutex_t qif_mutex;static char *qifnames[] = {		"lan", "du", "cip", "el", "ixe", "mfe", "clic", NULL};int	qif_num;qif_t	*qif_head;int	qif_verbose;/* ------------------------------------------------------------------------ *//* Function:    qif_startup                                                 *//* Returns:     int - 0 == success, -1 == failure                           *//* Parameters:  None.                                                       *//*                                                                          *//* Perform any initialisation of data structures related to managing qif's  *//* that is deemed necessary.                                                *//* ------------------------------------------------------------------------ */int qif_startup(){	qif_num = 0;	qif_head = NULL;	return 0;}void qif_stop(){	return;}void *q_to_ill(q)queue_t *q;{	ifinfo_t *ifp, *ifn;	char name[8], **s;	queue_t *rq;	int i, j;	rq = RD(q);	KMALLOC(ifp, ifinfo_t *, sizeof(ifinfo_t), KM_NOSLEEP);	if (!ifp)		return NULL;	READ_ENTER(&pfil_rw);	for (s = qifnames; *s; s++)		for (i = 0; i < 10; i++) {			sprintf(name, sizeof(name) - 1, "%s%d", *s, i);			name[sizeof(name) - 1] = '\0';			if (if_lookup_on_name(ifp, name, strlen(name) + 1)) {				if (ifp->ifi_rq == RD(q)->q_next) {					RW_EXIT(&pfil_rw);					ifp->ifi_name[strlen(name)] = '\0';					return ifp;				}				for (ifn = ifp->ifi_hash_next; ifn;				     ifn = ifn->ifi_hash_next) {					if (ifn->ifi_rq == RD(q)->q_next) {						RW_EXIT(&pfil_rw);						return ifp;					}				}			}		}	RW_EXIT(&pfil_rw);	KMFREE(ifp, sizeof(*ifp));	return NULL;}intqif_attach(rq)	queue_t *rq;{	packet_filter_hook_t *pfh;	ifinfo_t *ifi;	qif_t *qif;	ifi = q_to_ill(rq);	if (ifi == NULL) {		if (qif_verbose > 0)			cmn_err(CE_NOTE,				"PFIL: cannot find interface for rq %p",				(void *)rq);		return -1;	}	qif = rq->q_ptr;	if (qif->qf_bound == 1)		return 0;	qif->qf_sap = (ifi->ifi_sap[0] << 24) | (ifi->ifi_sap[1] << 16) |		      (ifi->ifi_sap[2] << 8) | ifi->ifi_sap[3];	qif->qf_ppa = ifi->ifi_ppa;	qif->qf_hl = ifi->ifi_hdr_length;	qif->qf_ill = ifi;	qif->qf_bound = 1;	strncpy(qif->qf_name, ifi->ifi_name, sizeof(qif->qf_name));	qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';	READ_ENTER(&pfh_sync.ph_lock);	pfh = pfil_hook_get(PFIL_IN, &pfh_sync);	for (; pfh; pfh = pfh->pfil_next)		if (pfh->pfil_func)			(void) (*pfh->pfil_func)(NULL, 0, qif, 0,						 qif, NULL);	RW_EXIT(&pfh_sync.ph_lock);	if (qif_verbose > 0)		cmn_err(CE_NOTE, "PFIL: attaching [%s]", qif->qf_name);	return 0;}qif_t *qif_new(q, mflags)	queue_t *q;	int mflags;{	qif_t *qif, *qf;	u_int i, l;	KMALLOC(qif, qif_t *, sizeof(qif_t), mflags);	if (qif == NULL) {		cmn_err(CE_NOTE, "PFIL: malloc(%d) for qif_t failed",			(int)sizeof(qif_t));		return NULL;	}	bzero((char *)qif, sizeof(qif));	qif->qf_qifsz = sizeof(*qif);	qif->qf_q = q;	qif->qf_oq = OTHERQ(q);	WRITE_ENTER(&pfil_rw);	qif->qf_num = qif_num++;	qif->qf_next = qif_head;	qif_head = qif;	RW_EXIT(&pfil_rw);	(void) sprintf(qif->qf_name, sizeof(qif->qf_name),		       "QIF%x", qif->qf_num);	return qif;}void qif_delete(qif, q)qif_t *qif;queue_t *q;{	packet_filter_hook_t *pfh;	ifinfo_t *ifp;	qif_t **qp;	int rm = 0;	if (qif == NULL)		return;	WRITE_ENTER(&pfil_rw);	if (qif->qf_bound && qif_verbose)		cmn_err(CE_NOTE, "PFIL: detaching [%s]", qif->qf_name);	for (qp = &qif_head; *qp; qp = &(*qp)->qf_next)		if (*qp == qif) {			*qp = qif->qf_next;			rm = 1;			break;		}	if (qif->qf_ill) {		READ_ENTER(&pfh_sync.ph_lock);		pfh = pfil_hook_get(PFIL_OUT, &pfh_sync);		for (; pfh; pfh = pfh->pfil_next)			if (pfh->pfil_func)				(void) (*pfh->pfil_func)(NULL, 0, qif,							 1, qif, NULL);		RW_EXIT(&pfh_sync.ph_lock);	}	RW_EXIT(&pfil_rw);	if (rm) {		ifp = qif->qf_ill;		if (ifp != NULL) {			KMFREE(ifp, sizeof(*ifp));		}		KMFREE(qif, qif->qf_qifsz);	}	return;}void *qif_iflookup(name, sap)char *name;int sap;{	qif_t *qif;	for (qif = qif_head; qif; qif = qif->qf_next)		if ((!sap || (qif->qf_sap == sap)) &&		    !strcmp(qif->qf_name, name))			break;	return qif;}void *ir_to_ill(ir)struct irinfo_s *ir;{	queue_t *q;	qif_t *qf;	for (qf = qif_head; qf; qf = qf->qf_next) {		q = qf->qf_q;		if (q && q->q_next && (RD(q->q_next) == ir->ir_rfq))			return qf->qf_ill;	}	return NULL;}void qif_update(qif, mp)qif_t *qif;mblk_t *mp;{	ifinfo_t ifi;	if (!qif->qf_ill)		return;	if (if_lookup_on_name(&ifi, qif->qf_name, strlen(qif->qf_name) + 1)) {		qif->qf_sap = (ifi.ifi_sap[0] << 24) | (ifi.ifi_sap[1] << 16) |			      (ifi.ifi_sap[2] << 8) | ifi.ifi_sap[3];		qif->qf_hl = ifi.ifi_hdr_length;		bcopy((char *)&ifi, (char *)qif->qf_ill, sizeof(ifi));	}	return;}/* ------------------------------------------------------------------------ *//* Function:    qif_walk                                                    *//* Returns:     qif_t *  - NULL == search failed, else pointer to qif_t     *//* Parameters:  qfp(IO) - pointer to the name                               *//*                                                                          *//* NOTE: it is assumed the caller has a lock on pfil_rw                     *//*                                                                          *//* Provide a function to enable the caller to enumerate through all of the  *//* qif_t's without being aware of the internal data structure used to store *//* them in.                                                                 *//* ------------------------------------------------------------------------ */qif_t *qif_walk(qif_t **qfp){	struct qif *qf, *qf2;	if (qfp == NULL)		return NULL;	qf = *qfp;	if (qf == NULL)		*qfp = qif_head;	else {		/*		 * Make sure the pointer being passed in exists as a current		 * object before returning its next value.		 */		for (qf2 = qif_head; qf2 != NULL; qf2 = qf2->qf_next)			if (qf2 == qf)				break;		if (qf2 == NULL)			*qfp = NULL;		else			*qfp = qf->qf_next;	}	return *qfp;}/* ------------------------------------------------------------------------ *//* Function:    qif_ipmp_update                                             *//* Returns:     void                                                        *//* Parameters:  ipmpconf(I) - pointer to an ill to match against            *//*                                                                          *//* Take an IPMP configuration string passed in to update the pfil config.   *//* The string may either indicate that an IPMP interface is to be deleted   *//* ("ipmp0=" - no NICs after the right of the '=') or created/changed if    *//* there is text after the '='.                                             *//* ------------------------------------------------------------------------ */void qif_ipmp_update(char *ipmpconf){	qif_t *qif, *qf;	int len, sap;	char *s;	sap = ETHERTYPE_IP;	if (!strncmp(ipmpconf, "v4:", 3)) {		ipmpconf += 3;	} else if (!strncmp(ipmpconf, "v6:", 3)) {#ifdef ETHERTYPE_IPV6		sap = ETHERTYPE_IPV6;		ipmpconf += 3;#else		return;#endif	} else		return;	s = strchr(ipmpconf, '=');	if (s != NULL) {		if (*(s + 1) == '\0')			*s = '\0';		else			*s++ = '\0';	}	if (s == NULL || *s == NULL) {		qif_ipmp_delete(ipmpconf);		return;	}	len = sizeof(qif_t) + strlen(s) + 1;	KMALLOC(qif, qif_t *, len, KM_NOSLEEP);	if (qif == NULL) {		cmn_err(CE_NOTE, "PFIL: malloc(%ld) for qif_t failed", len);		return;	}	WRITE_ENTER(&pfil_rw);	for (qf = qif_head; qf; qf = qf->qf_next) 		if (strcmp(qf->qf_name, ipmpconf) == 0)			break;	if (qf == NULL) {		qf = qif;		qif->qf_next = qif_head;		qif_head = qif;		qif->qf_flags |= QF_IPMP;		qif->qf_qifsz = len;		qif->qf_members = (char *)qif + sizeof(*qif);		strcpy(qif->qf_name, ipmpconf);	} else {		KMFREE(qif, len);		qif = qf;	}	RW_DOWNGRADE(&pfil_rw);	strcpy(qif->qf_members, s);	qif_ipmp_syncmaster(qif);	RW_EXIT(&pfil_rw);}/* ------------------------------------------------------------------------ *//* Function:    qif_ipmp_delete                                             *//* Returns:     void                                                        *//* Parameters:  qifname(I) - pointer to name of qif to delete               *//*                                                                          *//* Search for a qif structure that is named to match qifname, remove all    *//* references to it by others, delink and free it.                          *//* ------------------------------------------------------------------------ */void qif_ipmp_delete(char *qifname){	packet_filter_hook_t *pfh;	qif_t *qf, **qfp, *qif;	WRITE_ENTER(&pfil_rw);	for (qfp = &qif_head; (qif = *qfp) != NULL; qfp = &qif->qf_next) {		if ((qif->qf_flags & QF_IPMP) == 0)			continue;		if (strcmp(qif->qf_name, qifname) == 0) {			*qfp = qif->qf_next;			for (qf = qif_head; qf != NULL; qf = qf->qf_next)				if (qf->qf_ipmp == qif)					qf->qf_ipmp = NULL;			break;		}	}	RW_EXIT(&pfil_rw);	if (qif != NULL) {		pfh = pfil_hook_get(PFIL_OUT, &pfh_sync);		for (; pfh; pfh = pfh->pfil_next)			if (pfh->pfil_func)				(void) (*pfh->pfil_func)(NULL, 0, qif, 1,							 qif, NULL);		KMFREE(qif, qif->qf_qifsz);	}}/* ------------------------------------------------------------------------ *//* Function:    qif_ipmp_syncmaster                                         *//* Returns:     void                                                        *//* Parameters:  updated(I) - pointer to updated qif structure               *//* Locks:       pfil_rw                                                     *//*                                                                          *//* This function rechecks all the qif structures that aren't defined for    *//* IPMP to see if they are indeed members of the group pointed to by        *//* updated.  Ones that currently claim to be in updated are reset and       *//* rechecked in case they have become excluded. This function should be     *//* called for any new IPMP qif's created or when an IPMP qif changes.       *//* ------------------------------------------------------------------------ */void qif_ipmp_syncmaster(qif_t *updated, const int sap){	char *s, *t;	qif_t *qf;	for (qf = qif_head; qf != NULL; qf = qf->qf_next)  {		if ((qf->qf_flags & QF_IPMP) != 0)			continue;		if (qf->qf_sap != sap)			continue;		if (qf->qf_ipmp == updated)			qf->qf_ipmp = NULL;		for (s = updated->qf_members; s != NULL; ) {			t = strchr(s, ',');			if (t != NULL)				*t = '\0';			if (strcmp(qf->qf_name, s) == 0)				qf->qf_ipmp = updated;			if (t != NULL)				*t++ = ',';			s = t;		}	}}/* ------------------------------------------------------------------------ *//* Function:    qif_ipmp_syncslave                                          *//* Returns:     void                                                        *//* Parameters:  target(I) - pointer to updated qif structure                *//* Locks:       pfil_rw                                                     *//*                                                                          *//* Check through the list of qif's to see if there is an IPMP with a member *//* list that includes the one named by target.                              *//* ------------------------------------------------------------------------ */void qif_ipmp_syncslave(qif_t *target, const int sap){	char *s, *t;	qif_t *qf;	target->qf_ipmp = NULL;	/*	 * Recheck the entire list of qif's for any references to the one	 * we have just created/updated (updated).	 */	for (qf = qif_head; qf != NULL; qf = qf->qf_next)  {		if ((qf->qf_flags & QF_IPMP) == 0)			continue;		if (qf->qf_sap != sap)			continue;		for (s = qf->qf_members; s != NULL; ) {			t = strchr(s, ',');			if (t != NULL)				*t = '\0';			if (strcmp(target->qf_name, s) == 0)				target->qf_ipmp = qf;			if (t != NULL)				*t++ = ',';			s = t;			if (target->qf_ipmp == qf)				break;		}	}}/* ------------------------------------------------------------------------ *//* Function:    qif_hl_set                                                  *//* Returns:     void                                                        *//* Parameters:  ipmpconf(I) - string with header length setting for NIC     *//*                                                                          *//* For NICs that we cannot automatically determine the MAC header length of *//* we provide a manual crook to achieve that with.  The input syntax for    *//* the string is "[v4:|v6:]<ifname>=<length>"                               *//* ------------------------------------------------------------------------ */void qif_hl_set(char *ipmpconf){	qif_t *qif, *qf;	int len, sap;	char *s;	sap = ETHERTYPE_IP;	if (!strncmp(ipmpconf, "v4:", 3)) {		ipmpconf += 3;	} else if (!strncmp(ipmpconf, "v6:", 3)) {#ifdef ETHERTYPE_IPV6		sap = IP6_DL_SAP;		ipmpconf += 3;#else		return;#endif	}	s = strchr(ipmpconf, '=');	if (s != NULL) {		if (*(s + 1) == '\0')			*s = '\0';		else			*s++ = '\0';	}	if (s == NULL || *s == NULL)		return;	READ_ENTER(&pfil_rw);	for (qf = qif_head; qf; qf = qf->qf_next) 		if (strcmp(qf->qf_name, ipmpconf) == 0)			break;	if (qf != NULL) {		int hl = 0;		for (; *s != '\0'; s++) {			char c = *s;			if (c < '0' || c > '9')				return;			hl *= 10;			hl += c - '0'; 		}		qf->qf_hl = hl;	}	RW_EXIT(&pfil_rw);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -