📄 minimal-ppp.c
字号:
if (retv == 0) { state->xcps[i].restart_point = 0; /* Hack -- send with same ID on timeout. */ if (state->xcps[i].restart > 0) state->xcps[i].ident--; if (debugtimer) printf("Sending TO%c to %s\n", state->xcps[i].restart > 0 ? '+' : '-', state->xcps[i].name); send_event(state,state->xcps+i, state->xcps[i].restart > 0 ? evTOp : evTOm); } else /* Hack. */ state->xcps[i].restart_point = now+1; } /* If nothing waiting, then no need to read. */ if (retv == 0) continue; } /* Fetch input packet */ if (retv > 0) retv = read(state->sock,state->inbuffer,sizeof(state->inbuffer)); if (retv <= 0) { /* Wait for UDP peer to come up at least once. */ if (errno == ECONNREFUSED && !rcvd_anything) continue; /* Ignore interrupt nonsense. */ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; if (retv < 0) perror("read"); break; } if (showraw) buffer_print("Received",state->inbuffer,retv); rcvd_anything = 1; /* ACFC would go here. */ if (state->inbuffer[0] != 0xFF || state->inbuffer[1] != 0x03) { printf("Bad address and control field %02X %02X.\n", state->inbuffer[0],state->inbuffer[1]); continue; } /* PFC would go here. */ if ((state->inbuffer[2] & 1) != 0 || (state->inbuffer[3] & 1) == 0) { printf("Bad protocol field %02X %02X.\n", state->inbuffer[2],state->inbuffer[3]); continue; } /* Find XCP for indicated protocol */ proto = ntohs(*(unsigned short *)(state->inbuffer+2)); for (i = 0; i < Dim(state->xcps); i++) if (state->xcps[i].proto == proto) break; if (i >= Dim(state->xcps)) { /* Generate LCP Protocol-Reject for unknown things. */ printf("Unknown protocol %04X\n",proto); if (state->xcps[XCP_LCP].state == stOpened) { bp = code_id(state,&state->xcps[XCP_LCP], CODE_PROTO_REJ); i = sizeof(state->upbuf) - (bp-state->upbuf); retv -= 2; if (retv > i) retv = i; memcpy(bp,state->inbuffer+2,retv); retv += bp-state->upbuf; *(unsigned short *)(state->upbuf+2) = htons(retv-4); ppp_write(state,&state->xcps[XCP_LCP],state->upbuf,retv); } continue; } /* Remove HDLC headers and PPP Protocol Field and deliver */ state->bp = state->inbuffer+4; state->mlen = retv-4; (*state->xcps[i].deliver)(state,state->xcps+i); }}/* * Add current option to list of options to be sent in Configure-Reject. */voidset_reject(struct ppp_state *state, struct ppp_xcp *xcp, const unsigned char *bp){ int i; if (state->parse_state == psBad) return; /* If this is the first reject for this packet, then set up. */ if (state->parse_state != psRej) { state->up = code_reply(state,xcp,CODE_CONF_REJ); state->parse_state = psRej; } /* * Handle malformed options; make sure we don't send anything illegal * to the peer (even if he's sending us junk). */ if ((i = bp[1]) < 2) i = 2; memcpy(state->up,bp,i); state->up[1] = i; state->up += i;}/* * Add current option to list of options to be sent in Configure-Nak. */voidset_nak(struct ppp_state *state, struct ppp_xcp *xcp, int type, int len, const unsigned char *bp){ /* If we're rejecting, then no point in doing naks. */ if (state->parse_state == psBad || state->parse_state == psRej) return; /* If this is the first nak for this packet, then set up. */ if (state->parse_state != psNak) { state->up = code_reply(state,xcp,CODE_CONF_NAK); state->parse_state = psNak; } *state->up++ = type; *state->up++ = len; while (--len > 1) *state->up++ = *bp++;}/* * Check Configure-Request options from peer against list of * known, valid, and desired options. */intvalidate_request(struct ppp_state *state, struct ppp_xcp *xcp){ int rlen,i; const unsigned char *bp; const struct xcp_type *tp; state->parse_state = psOK; rlen = state->mlen; bp = state->bp; while (rlen > 0) { if (rlen < 2 || bp[1] > rlen) { state->parse_state = psBad; break; } for (tp = xcp->types; tp->type != -1; tp++) if (tp->type == bp[0]) break; if (tp->type == -1) set_reject(state,xcp,bp); else if (bp[1] < tp->minlen) set_nak(state,xcp,tp->type,tp->minlen,bp+2); else if (bp[1] > tp->maxlen) set_nak(state,xcp,tp->type,tp->maxlen,bp+2); else if (tp->validate_req == NULL) ; else (*tp->validate_req)(state,xcp,tp,bp+2,bp[1]); if ((i = bp[1]) < 2) i = 2; rlen -= i; bp += i; } if (state->parse_state == psNak || state->parse_state == psRej) { i = (state->up - state->upbuf) - 4; state->upbuf[6] = (i >> 8) & 0xFF; state->upbuf[7] = i & 0xFF; } return state->parse_state == psOK;}/* * Process options in a Configure-{Ack,Nak,Reject}. */voidprocess_rcx(struct ppp_state *state, struct ppp_xcp *xcp, unsigned char code){ int rlen,i,val; unsigned char *bp; const struct xcp_type *tp; struct option_state *os; rlen = state->mlen; bp = state->bp; while (rlen > 0) { if (rlen < 2 || bp[1] > rlen) break; for (tp = xcp->types; tp->type != -1; tp++) if (tp->type == bp[0]) break; if (tp->type != -1) { os = xcp->opts + (tp-xcp->types); if (code == CODE_CONF_REJ) os->state = osUnusable; else if (code == CODE_CONF_ACK || tp->validate_nak == NULL) { if (bp[1] > 6 || bp[1] <= 2) os->my_value = tp->default_value; else { val = bp[2]; if (bp[1] > 3) val = (val << 8) + bp[3]; if (bp[1] > 4) val = (val << 8) + bp[4]; if (bp[1] > 5) val = (val << 8) + bp[5]; os->my_value = val; } } else (*tp->validate_nak)(state,xcp,tp,bp+2,bp[1]); } if ((i = bp[1]) < 2) i = 2; rlen -= i; bp += i; }}/* * Standard negotiation entry point. This is assigned as the * 'delivery' function for control protocols, like LCP and IPCP. */voidstd_negotiation(struct ppp_state *state, struct ppp_xcp *xcp){ unsigned char code,id; unsigned short proto; int i,length; /* Validate overall message length */ if (state->mlen < 4) { printf("Malformed negotiation message; %d < 4\n", state->mlen); return; } code = *state->bp++; id = *state->bp++; length = (state->bp[0] << 8) + state->bp[1]; if (length > state->mlen) { printf("Truncated negotiation message; %d > %d\n", length,state->mlen); return; } if (length < state->mlen) { printf("Trimmed negotiation message; %d < %d\n", length,state->mlen); state->mlen = length; } state->bp += 2; state->mlen -= 4; if (showpackets) { show_neg_packet("RCVD",state,xcp,state->bp-4,state->mlen+4); } /* Now switch out on received code number */ switch (code) { case CODE_CONF_REQ: /* If request is good, then RCR+, if bad, then RCR- */ if (validate_request(state,xcp)) send_event(state,xcp,evRCRp); else send_event(state,xcp,evRCRm); break; case CODE_CONF_ACK: /* Configure-Ack ID number must match last sent. */ if (id != xcp->ident) break; /* Should validate contents against last req sent, but we don't. */ process_rcx(state,xcp,code); send_event(state,xcp,evRCA); break; case CODE_CONF_NAK: case CODE_CONF_REJ: /* Configure-Nak/Reject ID number must match last sent. */ if (id != xcp->ident) break; process_rcx(state,xcp,code); send_event(state,xcp,evRCN); break; case CODE_TERM_REQ: send_event(state,xcp,evRTR); break; case CODE_TERM_ACK: if (id != xcp->ident) break; send_event(state,xcp,evRTA); break; case CODE_CODE_REJ: code = *state->bp++; /* Peer cannot reject well-known code numbers. */ if (code != 0 && code < CODE_ECHO_REQ) { printf("Invalid code reject for %d\n",code); send_event(state,xcp,evRXJm); } else send_event(state,xcp,evRXJp); break; case CODE_PROTO_REJ: proto = (state->bp[0] << 8) + state->bp[1]; /* Peer cannot reject LCP! */ if (proto == state->xcps[XCP_LCP].proto) { printf("Peer protocol-rejected LCP itself!\n"); send_event(state,&state->xcps[XCP_LCP],evRXJm); } else { send_event(state,xcp,evRXJp); for (i = 0; i < Dim(state->xcps); i++) if (state->xcps[i].proto == proto) state->xcps[i].state = stInitial; } break; case CODE_ECHO_REQ: /* Should be sending a reply here. */ case CODE_DISCARD_REQ: send_event(state,xcp,evRXR); break; case CODE_ECHO_REP: /* ID number in Echo-Reply must match last echo sent. */ if (id != xcp->ident) break; send_event(state,xcp,evRXR); break; default: state->bp -= 4; send_event(state,xcp,evRUC); break; }}/* * Initialize an XCP (LCP or NCP). */voidinit_xcp(const char *name, struct ppp_xcp *xcp, void (*deliver)(struct ppp_state *state, struct ppp_xcp *xcp), const struct xcp_type *types, int ntypes, unsigned short proto){ struct option_state *os; xcp->name = name; xcp->state = stInitial; xcp->restart = 0; xcp->restart_point = 0; xcp->deliver = deliver; xcp->types = types; xcp->proto = proto; /* If no options, then no vector to store negotiated values. */ if (ntypes <= 0) { xcp->opts = NULL; return; } /* Otherwise, allocate vector and initialize options */ os = xcp->opts = (struct option_state *) malloc(ntypes*sizeof(struct option_state)); while (--ntypes >= 0) { os->my_value = os->peer_value = types->default_value; os->state = osUsable; os++; types++; }}/* * Initialize PPP state machine and add LCP and IPCP. */voidset_up_ppp(struct ppp_state *state, int sock){ state->phase = phDead; state->sock = sock; state->timeout_period = INITIAL_TIMEOUT; init_xcp("LCP",&state->xcps[XCP_LCP],std_negotiation,lcp_types, Dim(lcp_types)-1,PROT_LCP); init_xcp("IPCP",&state->xcps[XCP_IPCP],std_negotiation,ipcp_types, Dim(ipcp_types)-1,PROT_IPCP);}/* * Handle Configure-Request from peer. If it's in the range we think * it should be, then do nothing (allow Configure-Ack). Otherwise, * send Configure-Nak with something more appropriate. */voidipcp_addr_req(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len){ int addr; unsigned char lbuf[4]; struct option_state *os; addr = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3]; os = xcp->opts + (tp-xcp->types); if (addr != os->my_value && (addr & remote_ip_mask) == remote_ip_base) return; addr = xcp->opts[tp-xcp->types].peer_value; lbuf[0] = (addr >> 24) & 0xFF; lbuf[1] = (addr >> 16) & 0xFF; lbuf[2] = (addr >> 8) & 0xFF; lbuf[3] = addr & 0xFF; set_nak(state,xcp,tp->type,tp->minlen,lbuf);}/* * Got a Configure-Nak of our address. Just change; we're flexible. */voidipcp_addr_nak(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len){ xcp->opts[tp-xcp->types].my_value = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3];}/* * Show address. */voidipcp_addr_show(const struct ppp_state *state, const struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len){ struct in_addr addr; addr.s_addr = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3]; printf("%s",inet_ntoa(addr));}/* * Set local value (for Configure-Request). */voidset_option_value_lcl(struct ppp_xcp *xcp, int type, int value){ struct option_state *os; if ((os = find_option(xcp,type)) != NULL) os->my_value = value;}/* * Set desired value for peer (we'll Configure-Nak with this). */voidset_option_value_rem(struct ppp_xcp *xcp, int type, int value){ struct option_state *os; if ((os = find_option(xcp,type)) != NULL) os->peer_value = value;}intmain(argc,argv)int argc;char **argv;{ int sock,i; struct ppp_state mystate; myname = argv[0]; while ((i=getopt(argc,argv,"adpstv")) != EOF) switch (i) { case 'a': debugactions++; break; case 'd': showraw++; break; case 'p': debugphases++; break; case 's': debugstates++; break; case 't': debugtimer++; break; case 'v': showpackets++; break; case '?': usage(); return 1; } if ((sock = set_up_tunnel(argv+optind)) < 0) { usage(); return 1; } /* Request that IPCP go open! */ set_up_ppp(&mystate,sock); /* Set some random addresses to try */ srand(getpid()); set_option_value_lcl(&mystate.xcps[XCP_IPCP],3,0x0A000000+(rand()%1000)); set_option_value_rem(&mystate.xcps[XCP_IPCP],3,0x0A00000A+(rand()%1000)); /* Tell LCP to open */ send_event(&mystate,&mystate.xcps[XCP_IPCP],evOpen); signal(SIGALRM,alarm_handle); read_packets(&mystate); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -