📄 ip_fw.c.svn-base
字号:
#ifndef _WIN32 /* (no uid/gid checks for now) */
/* Protocol specific checks for uid only */
if (f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)) {
switch (proto) {
case IPPROTO_TCP:
{
struct inpcb *P;
if (offset == 1) /* cf. RFC 1858 */
goto bogusfrag;
if (offset != 0)
continue;
if (oif)
P = in_pcblookup_hash(&tcbinfo, dst_ip,
dst_port, src_ip, src_port, 0,
oif);
else
P = in_pcblookup_hash(&tcbinfo, src_ip,
src_port, dst_ip, dst_port, 0,
NULL);
if (P && P->inp_socket) {
if (f->fw_flg & IP_FW_F_UID) {
if (P->inp_socket->so_cred->cr_uid !=
f->fw_uid)
continue;
} else if (!groupmember(f->fw_gid,
P->inp_socket->so_cred))
continue;
} else
continue;
break;
}
case IPPROTO_UDP:
{
struct inpcb *P;
if (offset != 0)
continue;
if (oif)
P = in_pcblookup_hash(&udbinfo, dst_ip,
dst_port, src_ip, src_port, 1,
oif);
else
P = in_pcblookup_hash(&udbinfo, src_ip,
src_port, dst_ip, dst_port, 1,
NULL);
if (P && P->inp_socket) {
if (f->fw_flg & IP_FW_F_UID) {
if (P->inp_socket->so_cred->cr_uid !=
f->fw_uid)
continue;
} else if (!groupmember(f->fw_gid,
P->inp_socket->so_cred))
continue;
} else
continue;
break;
}
default:
continue;
}
}
#endif /* _WIN32 */
/* Protocol specific checks */
switch (proto) {
case IPPROTO_TCP:
{
struct tcphdr *tcp;
if (offset == 1) /* cf. RFC 1858 */
goto bogusfrag;
if (offset != 0) {
/*
* TCP flags and ports aren't available in this
* packet -- if this rule specified either one,
* we consider the rule a non-match.
*/
if (IP_FW_HAVEPORTS(f) != 0 ||
f->fw_tcpopt != f->fw_tcpnopt ||
f->fw_tcpf != f->fw_tcpnf)
continue;
break;
}
tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
if (f->fw_tcpopt != f->fw_tcpnopt && !tcpopts_match(tcp, f))
continue;
if (((f->fw_tcpf != f->fw_tcpnf) ||
(f->fw_ipflg & IP_FW_IF_TCPEST)) &&
!tcpflg_match(tcp, f))
continue;
goto check_ports;
}
case IPPROTO_UDP:
if (offset != 0) {
/*
* Port specification is unavailable -- if this
* rule specifies a port, we consider the rule
* a non-match.
*/
if (IP_FW_HAVEPORTS(f) )
continue;
break;
}
check_ports:
if (!port_match(&f->fw_uar.fw_pts[0],
IP_FW_GETNSRCP(f), ntohs(src_port),
f->fw_flg & IP_FW_F_SRNG,
f->fw_flg & IP_FW_F_SMSK))
continue;
if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)],
IP_FW_GETNDSTP(f), ntohs(dst_port),
f->fw_flg & IP_FW_F_DRNG,
f->fw_flg & IP_FW_F_DMSK))
continue;
break;
case IPPROTO_ICMP:
{
struct icmp *icmp;
if (offset != 0) /* Type isn't valid */
break;
icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl);
if (!icmptype_match(icmp, f))
continue;
break;
}
default:
break;
bogusfrag:
if (fw_verbose) {
if (m != NULL)
ipfw_report(NULL, ip, ip_off, ip_len, rif, oif);
else
printf("pullup failed\n");
}
goto dropit;
}
rnd_then_got_match:
if ( f->dont_match_prob && random() < f->dont_match_prob )
continue ;
got_match:
/*
* If not a dynamic match (q == NULL) and keep-state, install
* a new dynamic entry.
*/
if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) {
if (install_state(f, args)) /* error or limit violation */
goto dropit;
}
/* Update statistics */
f->fw_pcnt += 1;
f->fw_bcnt += ip_len;
f->timestamp = time_second;
/* Log to console if desired */
if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose && hlen > 0)
ipfw_report(f, ip, offset, ip_len, rif, oif);
/* Take appropriate action */
switch (f->fw_flg & IP_FW_F_COMMAND) {
case IP_FW_F_ACCEPT:
return(0);
case IP_FW_F_COUNT:
continue;
#ifdef IPDIVERT
case IP_FW_F_DIVERT:
*cookie = f->fw_number;
return(f->fw_divert_port);
case IP_FW_F_TEE:
*cookie = f->fw_number;
return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
#endif
case IP_FW_F_SKIPTO: /* XXX check */
if (f->next_rule_ptr == NULL)
f->next_rule_ptr = lookup_next_rule(f) ;
f = f->next_rule_ptr;
if (!f)
goto dropit;
goto again ;
case IP_FW_F_PIPE:
case IP_FW_F_QUEUE:
*flow_id = f ; /* XXX set flow id */
return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);
case IP_FW_F_FWD:
/* Change the next-hop address for this packet.
* Initially we'll only worry about directly
* reachable next-hop's, but ultimately
* we will work out for next-hops that aren't
* direct the route we would take for it. We
* [cs]ould leave this latter problem to
* ip_output.c. We hope to high [name the abode of
* your favourite deity] that ip_output doesn't modify
* the new value of next_hop (which is dst there)
* XXX warning-- there is a dangerous reference here
* from next_hop to a field within the rule. If the
* rule is deleted, weird things might occur.
*/
if (next_hop != NULL /* Make sure, first... */
&& (q == NULL || direction == MATCH_FORWARD) )
*next_hop = &(f->fw_fwd_ip);
return(0); /* Allow the packet */
}
/* Deny/reject this packet using this rule */
break;
}
/* Rule IPFW_DEFAULT_RULE should always be there and match */
KASSERT(f != NULL, ("ip_fw: no chain"));
/*
* At this point, we're going to drop the packet.
* Send a reject notice if all of the following are true:
*
* - The packet matched a reject rule
* - The packet is not an ICMP packet, or is an ICMP query packet
* - The packet is not a multicast or broadcast packet
*/
if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
&& (proto != IPPROTO_ICMP || is_icmp_query(ip))
&& !((*m)->m_flags & (M_BCAST|M_MCAST))
&& !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
/* Must convert to host order for icmp_error() etc. */
#ifndef _WIN32
if (BRIDGED) {
#endif
ip->ip_len = ntohs(ip->ip_len);
ip->ip_off = ntohs(ip->ip_off);
#ifndef _WIN32
}
#endif
switch (f->fw_reject_code) {
case IP_FW_REJECT_RST:
{
/* XXX warning, this code writes into the mbuf */
struct tcphdr *const tcp =
(struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
if (offset != 0 || (tcp->th_flags & TH_RST))
break;
ti.ti_i = *((struct ipovly *) ip);
ti.ti_t = *tcp;
bcopy(&ti, ip, sizeof(ti));
NTOHL(tip->ti_seq);
NTOHL(tip->ti_ack);
tip->ti_len = ip_len - hlen - (tip->ti_off << 2);
if (tcp->th_flags & TH_ACK) {
tcp_respond(NULL, (void *)ip, tcp, *m,
(tcp_seq)0, tcp->th_ack, TH_RST);
} else {
if (tcp->th_flags & TH_SYN)
tip->ti_len++;
tcp_respond(NULL, (void *)ip, tcp, *m,
tip->ti_seq + tip->ti_len,
(tcp_seq)0, TH_RST|TH_ACK);
}
*m = NULL;
break;
}
default: /* Send an ICMP unreachable using code */
icmp_error(*m, ICMP_UNREACH,
f->fw_reject_code, 0L, 0);
*m = NULL;
break;
}
}
dropit:
/*
* Finally, drop the packet.
*/
return(IP_FW_PORT_DENY_FLAG);
#undef BRIDGED
}
/*
* when a rule is added/deleted, zero the direct pointers within
* all firewall rules. These will be reconstructed on the fly
* as packets are matched.
* Must be called at splimp().
*/
static void
flush_rule_ptrs()
{
struct ip_fw *fcp ;
LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
fcp->next_rule_ptr = NULL ;
}
}
void
flush_pipe_ptrs(struct dn_flow_set *match)
{
struct ip_fw *fcp ;
LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
if (match == NULL || fcp->pipe_ptr == match)
fcp->pipe_ptr = NULL;
}
}
static int
add_entry(struct ip_fw_head *head, struct ip_fw *rule)
{
struct ip_fw *ftmp, *fcp, *fcpl;
u_short nbr = 0;
int s;
ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO);
if (!ftmp)
return (ENOSPC);
bcopy(rule, ftmp, sizeof(*ftmp));
ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
ftmp->fw_pcnt = 0L;
ftmp->fw_bcnt = 0L;
ftmp->next_rule_ptr = NULL ;
ftmp->pipe_ptr = NULL ;
s = splimp();
if (LIST_FIRST(head) == 0) {
LIST_INSERT_HEAD(head, ftmp, next);
goto done;
}
/* If entry number is 0, find highest numbered rule and add 100 */
if (ftmp->fw_number == 0) {
LIST_FOREACH(fcp, head, next) {
if (fcp->fw_number != IPFW_DEFAULT_RULE)
nbr = fcp->fw_number;
else
break;
}
if (nbr < IPFW_DEFAULT_RULE - 100)
nbr += 100;
ftmp->fw_number = rule->fw_number = nbr;
}
/* Got a valid number; now insert it, keeping the list ordered */
fcpl = NULL ;
LIST_FOREACH(fcp, head, next) {
if (fcp->fw_number > ftmp->fw_number) {
if (fcpl) {
LIST_INSERT_AFTER(fcpl, ftmp, next);
} else {
LIST_INSERT_HEAD(head, ftmp, next);
}
break;
} else {
fcpl = fcp;
}
}
flush_rule_ptrs();
done:
static_count++;
splx(s);
DEB(printf("++ installed rule %d, static count now %d\n",
ftmp->fw_number, static_count);)
return (0);
}
/**
* free storage associated with a static rule entry (including
* dependent dynamic rules), and zeroes rule pointers to avoid
* dangling pointer dereferences.
* @return a pointer to the next entry.
* Must be called at splimp() and with a non-null argument.
*/
static struct ip_fw *
free_chain(struct ip_fw *fcp)
{
struct ip_fw *n;
n = LIST_NEXT(fcp, next);
DELETE_DYN_CHAIN(fcp);
LIST_REMOVE(fcp, next);
static_count--;
if (DUMMYNET_LOADED)
ip_dn_ruledel_ptr(fcp) ;
flush_rule_ptrs(); /* more efficient to do outside the loop */
free(fcp, M_IPFW);
return n;
}
/**
* remove all rules with given number.
*/
static int
del_entry(struct ip_fw_head *chainptr, u_short number)
{
struct ip_fw *rule;
if (number != IPFW_DEFAULT_RULE) {
LIST_FOREACH(rule, chainptr, next) {
if (rule->fw_number == number) {
int s ;
s = splimp(); /* prevent access to rules while removing */
while (rule && rule->fw_number == number)
rule = free_chain(rule);
/* XXX could move flush_rule_ptrs() here */
splx(s);
return 0 ;
}
}
}
return (EINVAL);
}
/**
* Reset some or all counters on firewall rules.
* @arg frwl is null to clear all entries, or contains a specific
* rule number.
* @arg log_only is 1 if we only want to reset logs, zero otherwise.
*/
static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -