o Drop packets that fail the dial filter when we're in

phase DEAD.  They'll almost definitely have timed out
  by the time we dial anyway.
o Log dial filters again (LogTCPIP).
o Make DEBUG diagnostics for filter checking actually mean
  something to the common observer.
o Do our best to keep any already-configured IP numbers at
  IPCP negotiation time.  We always first request our configured
  IP, and if the peer asks for an invalid IP, we NAK with HISADDR

Cosmetic:
  o Add a linefeed to the `set timeout' arg count error message.
  o Log unacceptable address errors to LogPHASE if LogIPCP is
    switched off.
  o Fix ``destination system not found'' error message.
  o Get out immediately if we get a fatal error before entering
    the main loop.
This commit is contained in:
Brian Somers 1998-04-03 19:25:07 +00:00
parent 92f4ff1ccd
commit 8390b57662
7 changed files with 199 additions and 101 deletions

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bundle.c,v 1.1.2.33 1998/03/25 18:38:38 brian Exp $
* $Id: bundle.c,v 1.1.2.34 1998/04/03 19:21:06 brian Exp $
*/
#include <sys/param.h>
@ -533,6 +533,7 @@ bundle_Create(const char *prefix)
bundle.filter.out.fragok = bundle.filter.out.logok = 1;
bundle.filter.out.name = "OUT";
bundle.filter.dial.name = "DIAL";
bundle.filter.dial.logok = 1;
bundle.filter.alive.name = "ALIVE";
bundle.filter.alive.logok = 1;
memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: command.c,v 1.131.2.47 1998/04/03 19:24:29 brian Exp $
* $Id: command.c,v 1.131.2.48 1998/04/03 19:24:45 brian Exp $
*
*/
#include <sys/param.h>
@ -1335,7 +1335,7 @@ SetVariable(struct cmdargs const *arg)
break;
case VAR_IDLETIMEOUT:
if (arg->argc > 1)
err = "Too many idle timeout values";
err = "Too many idle timeout values\n";
else if (arg->argc == 1)
bundle_SetIdleTimer(arg->bundle, atoi(argp));
if (err)

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: filter.c,v 1.22.2.9 1998/03/16 22:53:42 brian Exp $
* $Id: filter.c,v 1.22.2.10 1998/04/03 19:21:19 brian Exp $
*
* TODO: Shoud send ICMP error message when we discard packets.
*/
@ -57,6 +57,9 @@
#include "mp.h"
#include "bundle.h"
static int filter_Nam2Proto(int, char const *const *);
static int filter_Nam2Op(const char *);
static const u_long netmasks[33] = {
0x00000000,
0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
@ -123,25 +126,6 @@ ParseAddr(struct ipcp *ipcp, int argc, char const *const *argv,
return (1);
}
static int
ParseProto(int argc, char const *const *argv)
{
int proto;
if (argc < 1)
return (P_NONE);
if (!strcmp(*argv, "tcp"))
proto = P_TCP;
else if (!strcmp(*argv, "udp"))
proto = P_UDP;
else if (!strcmp(*argv, "icmp"))
proto = P_ICMP;
else
proto = P_NONE;
return (proto);
}
static int
ParsePort(const char *service, int proto)
{
@ -188,9 +172,7 @@ ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
/* permit/deny all ICMP types */
tgt->opt.srcop = OP_NONE;
break;
default:
LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
return (0);
case 3:
if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) {
type = strtol(argv[2], &cp, 0);
@ -202,24 +184,14 @@ ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
tgt->opt.srcport = type;
}
break;
default:
LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
return (0);
}
return (1);
}
static int
ParseOp(const char *cp)
{
int op = OP_NONE;
if (!strcmp(cp, "eq"))
op = OP_EQ;
else if (!strcmp(cp, "gt"))
op = OP_GT;
else if (!strcmp(cp, "lt"))
op = OP_LT;
return (op);
}
/*
* UDP Syntax: [src op port] [dst op port]
*/
@ -236,7 +208,7 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
}
if (argc >= 3 && !strcmp(*argv, "src")) {
tgt->opt.srcop = ParseOp(argv[1]);
tgt->opt.srcop = filter_Nam2Op(argv[1]);
if (tgt->opt.srcop == OP_NONE) {
LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
return (0);
@ -250,7 +222,7 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
return (1);
}
if (argc >= 3 && !strcmp(argv[0], "dst")) {
tgt->opt.dstop = ParseOp(argv[1]);
tgt->opt.dstop = filter_Nam2Op(argv[1]);
if (tgt->opt.dstop == OP_NONE) {
LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
return (0);
@ -276,8 +248,6 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
return (0);
}
static const char *opname[] = {"none", "eq", "gt", NULL, "lt"};
static int
Parse(struct ipcp *ipcp, int argc, char const *const *argv,
struct filterent *ofp)
@ -338,20 +308,20 @@ Parse(struct ipcp *ipcp, int argc, char const *const *argv,
argv++;
}
}
proto = ParseProto(argc, argv);
proto = filter_Nam2Proto(argc, argv);
if (proto == P_NONE) {
if (ParseAddr(ipcp, argc, argv, &filterdata.saddr, &filterdata.smask,
&filterdata.swidth)) {
argc--;
argv++;
proto = ParseProto(argc, argv);
proto = filter_Nam2Proto(argc, argv);
if (proto == P_NONE) {
if (ParseAddr(ipcp, argc, argv, &filterdata.daddr, &filterdata.dmask,
&filterdata.dwidth)) {
argc--;
argv++;
}
proto = ParseProto(argc, argv);
proto = filter_Nam2Proto(argc, argv);
if (proto != P_NONE) {
argc--;
argv++;
@ -390,10 +360,10 @@ Parse(struct ipcp *ipcp, int argc, char const *const *argv,
LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dmask));
LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto);
LogPrintf(LogDEBUG, "Parse: src: %s (%d)\n", opname[filterdata.opt.srcop],
filterdata.opt.srcport);
LogPrintf(LogDEBUG, "Parse: dst: %s (%d)\n", opname[filterdata.opt.dstop],
filterdata.opt.dstport);
LogPrintf(LogDEBUG, "Parse: src: %s (%d)\n",
filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport);
LogPrintf(LogDEBUG, "Parse: dst: %s (%d)\n",
filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport);
LogPrintf(LogDEBUG, "Parse: estab: %d\n", filterdata.opt.estab);
if (val)
@ -424,8 +394,12 @@ SetFilter(struct cmdargs const *arg)
return 0;
}
static const char *protoname[] = { "none", "tcp", "udp", "icmp" };
static const char *actname[] = { "none ", "permit ", "deny " };
const char *
filter_Action2Nam(int act)
{
static const char *actname[] = { "none ", "permit ", "deny " };
return actname[act & (A_PERMIT|A_DENY)];
}
static void
doShowFilter(struct filterent *fp)
@ -434,8 +408,7 @@ doShowFilter(struct filterent *fp)
for (n = 0; n < MAXFILTERS; n++, fp++) {
if (fp->action != A_NONE) {
prompt_Printf(&prompt, " %2d %s", n,
actname[fp->action & (A_PERMIT|A_DENY)]);
prompt_Printf(&prompt, " %2d %s", n, filter_Action2Nam(fp->action));
if (fp->action & A_UHOST)
prompt_Printf(&prompt, "host ");
else if (fp->action & A_UPORT)
@ -445,13 +418,13 @@ doShowFilter(struct filterent *fp)
prompt_Printf(&prompt, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
prompt_Printf(&prompt, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
if (fp->proto) {
prompt_Printf(&prompt, "%s", protoname[fp->proto]);
prompt_Printf(&prompt, "%s", filter_Proto2Nam(fp->proto));
if (fp->opt.srcop)
prompt_Printf(&prompt, " src %s %d", opname[fp->opt.srcop],
prompt_Printf(&prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop),
fp->opt.srcport);
if (fp->opt.dstop)
prompt_Printf(&prompt, " dst %s %d", opname[fp->opt.dstop],
prompt_Printf(&prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop),
fp->opt.dstport);
if (fp->opt.estab)
prompt_Printf(&prompt, " estab");
@ -500,3 +473,51 @@ ShowFilter(struct cmdargs const *arg)
return 0;
}
static const char *protoname[] = { "none", "tcp", "udp", "icmp" };
const char *
filter_Proto2Nam(int proto)
{
if (proto >= sizeof protoname / sizeof protoname[0])
return "unknown";
return protoname[proto];
}
static int
filter_Nam2Proto(int argc, char const *const *argv)
{
int proto;
if (argc == 0)
proto = 0;
else
for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--)
if (!strcasecmp(*argv, protoname[proto]))
break;
return proto;
}
static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"};
const char *
filter_Op2Nam(int op)
{
if (op >= sizeof opname / sizeof opname[0])
return "unknown";
return opname[op];
}
static int
filter_Nam2Op(const char *cp)
{
int op;
for (op = sizeof opname / sizeof opname[0] - 1; op; op--)
if (!strcasecmp(cp, opname[op]))
break;
return op;
}

View File

@ -15,7 +15,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: filter.h,v 1.11.2.1 1998/03/13 21:07:32 brian Exp $
* $Id: filter.h,v 1.11.2.2 1998/03/16 22:52:07 brian Exp $
*
* TODO:
*/
@ -82,3 +82,6 @@ extern int ParseAddr(struct ipcp *, int, char const *const *, struct in_addr *,
struct in_addr *, int *);
extern int ShowFilter(struct cmdargs const *);
extern int SetFilter(struct cmdargs const *);
extern const char * filter_Action2Nam(int);
extern const char *filter_Proto2Nam(int);
extern const char *filter_Op2Nam(int);

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: ip.c,v 1.38.2.16 1998/03/24 18:47:04 brian Exp $
* $Id: ip.c,v 1.38.2.17 1998/04/03 19:21:24 brian Exp $
*
* TODO:
* o Return ICMP message for filterd packet
@ -103,16 +103,17 @@ PortMatch(int op, u_short pport, u_short rport)
static int
FilterCheck(struct ip *pip, struct filter *filter)
{
int gotinfo, cproto, estab, n;
int gotinfo, cproto, estab, n, len, didname;
struct tcphdr *th;
struct udphdr *uh;
struct icmp *ih;
char *ptop;
u_short sport, dport;
struct filterent *fp = filter->rule;
char dbuff[100];
if (fp->action) {
cproto = gotinfo = estab = 0;
cproto = gotinfo = estab = didname = 0;
sport = dport = 0;
for (n = 0; n < MAXFILTERS; n++) {
if (fp->action) {
@ -120,7 +121,10 @@ FilterCheck(struct ip *pip, struct filter *filter)
if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
return (A_PERMIT);
LogPrintf(LogDEBUG, "rule = %d\n", n);
if (!didname)
LogPrintf(LogDEBUG, "%s filter:\n", filter->name);
didname = 1;
if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
(fp->saddr.s_addr & fp->smask.s_addr) &&
(pip->ip_dst.s_addr & fp->dmask.s_addr) ==
@ -134,14 +138,19 @@ FilterCheck(struct ip *pip, struct filter *filter)
cproto = P_ICMP;
ih = (struct icmp *) ptop;
sport = ih->icmp_type;
estab = 1;
estab = -1;
if (LogIsKept(LogDEBUG))
snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
break;
case IPPROTO_UDP:
cproto = P_UDP;
uh = (struct udphdr *) ptop;
sport = ntohs(uh->uh_sport);
dport = ntohs(uh->uh_dport);
estab = 1;
estab = -1;
if (LogIsKept(LogDEBUG))
snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
sport, dport);
break;
case IPPROTO_TCP:
cproto = P_TCP;
@ -149,21 +158,44 @@ FilterCheck(struct ip *pip, struct filter *filter)
sport = ntohs(th->th_sport);
dport = ntohs(th->th_dport);
estab = (th->th_flags & TH_ACK);
if (estab == 0)
LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
th->th_flags, sport, dport);
if (LogIsKept(LogDEBUG) && !estab)
snprintf(dbuff, sizeof dbuff,
"flags = %02x, sport = %d, dport = %d",
th->th_flags, sport, dport);
break;
default:
return (A_DENY);/* We'll block unknown type of packet */
return (A_DENY); /* We'll block unknown type of packet */
}
if (LogIsKept(LogDEBUG)) {
if (estab != -1) {
len = strlen(dbuff);
snprintf(dbuff + len, sizeof dbuff - len, ", estab = %d",
estab);
}
LogPrintf(LogDEBUG, " Filter: proto = %s, %s\n",
filter_Proto2Nam(cproto), dbuff);
}
gotinfo = 1;
LogPrintf(LogDEBUG, "dir = %p, proto = %d, srcop = %d,"
" dstop = %d, estab = %d\n", fp, cproto,
fp->opt.srcop, fp->opt.dstop, estab);
}
LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
" dport = %d\n", n, cproto, sport, dport);
LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
if (LogIsKept(LogDEBUG)) {
if (fp->opt.srcop != OP_NONE) {
snprintf(dbuff, sizeof dbuff, ", src %s %d",
filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
len = strlen(dbuff);
} else
len = 0;
if (fp->opt.dstop != OP_NONE) {
snprintf(dbuff + len, sizeof dbuff - len,
", dst %s %d", filter_Op2Nam(fp->opt.dstop),
fp->opt.dstport);
} else if (!len)
*dbuff = '\0';
LogPrintf(LogDEBUG, " rule = %d: Address match, "
"check against proto %s%s, action = %s\n",
n, filter_Proto2Nam(fp->proto),
dbuff, filter_Action2Nam(fp->action));
}
if (cproto == fp->proto) {
if ((fp->opt.srcop == OP_NONE ||
@ -178,10 +210,12 @@ FilterCheck(struct ip *pip, struct filter *filter)
}
} else {
/* Address is mached. Make a decision. */
LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
LogPrintf(LogDEBUG, " rule = %d: Address match, action = %s\n", n,
filter_Action2Nam(fp->action));
return (fp->action);
}
}
} else
LogPrintf(LogDEBUG, " rule = %d: Address mismatch\n", n);
}
fp++;
}

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: ipcp.c,v 1.50.2.28 1998/04/03 19:21:28 brian Exp $
* $Id: ipcp.c,v 1.50.2.29 1998/04/03 19:23:59 brian Exp $
*
* TODO:
* o More RFC1772 backwoard compatibility
@ -273,16 +273,25 @@ ipcp_Setup(struct ipcp *ipcp)
ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
ipcp->peer_compproto = 0;
/*
* Some implementations of PPP require that we send a
* *special* value as our address, even though the rfc specifies
* full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
*/
if (ipcp->cfg.HaveTriggerAddress) {
/*
* Some implementations of PPP require that we send a
* *special* value as our address, even though the rfc specifies
* full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
*/
ipcp->my_ip = ipcp->cfg.TriggerAddress;
LogPrintf(LogIPCP, "Using trigger address %s\n",
inet_ntoa(ipcp->cfg.TriggerAddress));
} else
} else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
(ipcp->cfg.my_range.ipaddr.s_addr &
ipcp->cfg.my_range.mask.s_addr))
/*
* Otherwise, if we've been assigned an IP number before, we really
* want to keep the same IP number so that we can keep any existing
* connections that are bound to that IP.
*/
ipcp->my_ip = ipcp->my_ifip;
else
ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
if (Enabled(ConfVjcomp))
@ -625,8 +634,18 @@ IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
ipaddr, 1)) {
LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
inet_ntoa(ipaddr));
ipcp->peer_ip = ChooseHisAddr
(fp->bundle, ipcp->cfg.my_range.ipaddr);
if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
/*
* If we've already got a valid address configured for the peer
* (in AUTO mode), try NAKing with that so that we don't
* have to upset things too much.
*/
ipcp->peer_ip = ipcp->peer_ifip;
else
/* Just pick an IP number from our list */
ipcp->peer_ip = ChooseHisAddr
(fp->bundle, ipcp->cfg.my_range.ipaddr);
if (ipcp->peer_ip.s_addr == INADDR_ANY) {
memcpy(dec->rejend, cp, length);
dec->rejend += length;
@ -639,11 +658,17 @@ IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
}
} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
/*
* If destination address is not acceptable, insist to use what we
* If destination address is not acceptable, NAK with what we
* want to use.
*/
memcpy(dec->nakend, cp, 2);
memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
(ipcp->cfg.peer_range.ipaddr.s_addr &
ipcp->cfg.peer_range.mask.s_addr))
/* We prefer the already-configured address */
memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
else
memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
dec->nakend += length;
break;
}
@ -659,7 +684,8 @@ IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
ipcp->my_ip = ipaddr;
} else {
LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogPHASE,
"%s: Unacceptable address!\n", inet_ntoa(ipaddr));
FsmClose(&ipcp->fsm);
}
break;

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: main.c,v 1.121.2.40 1998/04/03 19:21:36 brian Exp $
* $Id: main.c,v 1.121.2.41 1998/04/03 19:24:17 brian Exp $
*
* TODO:
* o Add commands for traffic summary, version display, etc.
@ -395,9 +395,8 @@ main(int argc, char **argv)
if (label) {
if (SelectSystem(bundle, label, CONFFILE) < 0) {
LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
GetLabel());
Cleanup(EX_START);
prompt_Printf(&prompt, "Destination system (%s) not found.\n", label);
AbortProgram(EX_START);
}
/*
* We don't SetLabel() 'till now in case SelectSystem() has an
@ -406,9 +405,9 @@ main(int argc, char **argv)
SetLabel(label);
if (mode & MODE_AUTO &&
bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for auto mode.\n",
label);
Cleanup(EX_START);
prompt_Printf(&prompt, "You must \"set ifaddr\" in label %s for "
"auto mode.\n", label);
AbortProgram(EX_START);
}
}
@ -419,13 +418,13 @@ main(int argc, char **argv)
if (mode & MODE_BACKGROUND && pipe(bgpipe)) {
LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
Cleanup(EX_SOCK);
AbortProgram(EX_SOCK);
}
bgpid = fork();
if (bgpid == -1) {
LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
Cleanup(EX_SOCK);
AbortProgram(EX_SOCK);
}
if (bgpid) {
@ -615,9 +614,23 @@ DoLoop(struct bundle *bundle)
* Process on-demand dialup. Output packets are queued within tunnel
* device until IPCP is opened.
*/
if (bundle_Phase(bundle) == PHASE_DEAD && (mode & MODE_AUTO) &&
(pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
bundle_Open(bundle, NULL);
if (bundle_Phase(bundle) == PHASE_DEAD)
/*
* Note, we must be in AUTO mode :-/ otherwise our interface should
* *not* be UP and we can't receive data
*/
if ((mode & MODE_AUTO) &&
(pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
bundle_Open(bundle, NULL);
else
/*
* Drop the packet. If we were to queue it, we'd just end up with
* a pile of timed-out data in our output queue by the time we get
* around to actually dialing. We'd also prematurely reach the
* threshold at which we stop select()ing to read() the tun
* device - breaking auto-dial.
*/
continue;
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
if (pri >= 0) {