📄 minimal-ppp.c
字号:
printf(" %04X: ",i); for (j = i; j < len && j < i+16; j++) printf(" %02X",buf[j]); putchar('\n'); }}/* Print text string safely. */voidsafe_string(const unsigned char *bp, int len){ char chr; putchar('"'); while (--len >= 0) { chr = *bp++; if (isascii(chr) && isprint(chr)) putchar(chr); else printf("\\%03o",chr); } putchar('"');}/* Show all options in negotiation message. */voidoption_show(const struct ppp_state *state, const struct ppp_xcp *xcp, const unsigned char *bp, int rlen){ int i; const struct xcp_type *tp; while (rlen > 0) { putchar(' '); if (rlen < 2) { printf("[trail %02X]\n",bp[0]); break; } if (bp[1] > rlen) { printf("[trunc %02X %d>%d]\n",bp[0],bp[1],rlen); break; } for (tp = xcp->types; tp->type != -1; tp++) if (tp->type == bp[0]) break; if (tp->show != NULL) { /* Valid option; use defined printing routine */ (*tp->show)(state,xcp,tp,bp+2,bp[1]); } else { /* Undefined option; just dump contents. */ if (tp->name == NULL) printf("%02X:",bp[0]); else printf("%s:",tp->name); for (i = 2; i < bp[1]; i++) printf("%02X",bp[i]); } if ((i = bp[1]) < 2) i = 2; rlen -= i; bp += i; }}/* * Show a negotiation packet. * Assumes 'bp' points to the code number (after PPP Protocol ID). */voidshow_neg_packet(const char *inout, const struct ppp_state *state, const struct ppp_xcp *xcp, const unsigned char *bp, int len){ int code, id, length; code = *bp++; id = *bp++; length = (bp[0] << 8) + bp[1]; bp += 2; if (len > length) len = length; len -= 4; printf("%s %s ",inout,xcp->name); if (code < Dim(code_str) && code_str[code] != NULL) printf("%s",code_str[code]); else printf("code:%d",code); printf(" ID:%d",id); if ((code == CODE_CONF_ACK || code == CODE_CONF_NAK || code == CODE_CONF_REJ || code == CODE_TERM_ACK || code == CODE_ECHO_REP) && id != xcp->ident) printf(" **ERR**"); printf(" len:%d",length); switch (code) { case CODE_CONF_REQ: case CODE_CONF_ACK: case CODE_CONF_NAK: case CODE_CONF_REJ: option_show(state,xcp,bp,len); break; case CODE_TERM_REQ: case CODE_TERM_ACK: if (len > 0) { putchar(' '); safe_string(bp,len); } break; case CODE_CODE_REJ: printf(" code %d",*bp); break; case CODE_PROTO_REJ: printf(" protocol %02X%02X",bp[0],bp[1]); break; case CODE_ECHO_REQ: case CODE_ECHO_REP: case CODE_DISCARD_REQ: if (len >= 4) printf(" magic %02X%02X%02X%02X",bp[0],bp[1],bp[2],bp[3]); if (len > 4) { putchar(' '); safe_string(bp+4,len-4); } break; } putchar('\n');}/* * Write packet to tunnel. Display contents if debugging. * (Wrapper around recalcitrant system call interface.) */voidppp_write(const struct ppp_state *state, const struct ppp_xcp *xcp, const unsigned char *buf, int len){ int retv,sock; if (showraw) buffer_print("Transmitting",buf,len); if (showpackets) { retv = buf[0] == 0xFF ? 2 : 0; retv += buf[retv] & 1 ? 1 : 2; show_neg_packet("SENT",state,xcp,buf+retv,len-retv); } sock = state->sock; for (;;) { retv = write(sock,buf,len); if (retv < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; perror("write"); exit(1); } break; }}/* * Insert HDLC Address/Control and PPP protocol fields. */unsigned char *set_up_acpf(unsigned char *buf, int proto){ buf[0] = 0xFF; buf[1] = 0x03; buf[2] = proto>>8; buf[3] = proto&0xFF; return buf+4;}/* * Set up buffer for a new message (Configure-Request, Protocol-Reject, * Echo-Request, or Discard-Request). */unsigned char *code_id(struct ppp_state *state, struct ppp_xcp *xcp, int code){ unsigned char *buf; buf = set_up_acpf(state->upbuf,xcp->proto); *buf++ = code; *buf++ = ++xcp->ident; *buf++ = 0; *buf++ = 4; return buf;}/* * Set up buffer for a reply to a previous message (Configure-Ack, * Configure-Nak, Configure-Reject, Echo-Reply). */unsigned char *code_reply(struct ppp_state *state, struct ppp_xcp *xcp, int code){ unsigned char *buf; buf = set_up_acpf(state->upbuf,xcp->proto); *buf++ = code; *buf++ = state->inbuffer[5]; *buf++ = 0; *buf++ = 4; return buf;}/* * Find a given option in the list for an XCP. */struct option_state *find_option(const struct ppp_xcp *xcp, int type){ const struct xcp_type *tp; for (tp = xcp->types; tp->type != -1; tp++) if (tp->type == type) return xcp->opts+(tp-xcp->types); return NULL;}/* * Loop over all known options and insert into a Configure-Request * being built. */voidcreate_request(struct ppp_state *state, struct ppp_xcp *xcp){ unsigned char *bp,*obp; const struct xcp_type *tp; struct option_state *os; obp = bp = code_id(state,xcp,CODE_CONF_REQ); for (tp = xcp->types, os = xcp->opts; tp->type != -1; tp++, os++) { if (os->state == osUnusable) continue; if (!tp->flag && os->my_value == tp->default_value) continue; bp[0] = tp->type; bp[1] = tp->minlen; if (tp->minlen > 2) bp[2] = (os->my_value >> (8 * (tp->minlen-3))) & 0xFF; if (tp->minlen > 3) bp[3] = (os->my_value >> (8 * (tp->minlen-4))) & 0xFF; if (tp->minlen > 4) bp[4] = (os->my_value >> (8 * (tp->minlen-5))) & 0xFF; if (tp->minlen > 5) bp[5] = os->my_value & 0xFF; bp += bp[1]; } *(unsigned short *)(obp - 2) = htons((bp-obp)+4); state->up = bp;}/* * We've gotten a Configure-Request we like (RCR+), so we're agreeing * with the peer. Set up to send Configure-Ack. */voidcopy_peer_values(const struct ppp_state *state, struct ppp_xcp *xcp){ const unsigned char *bp; const struct xcp_type *tp; struct option_state *os; int rlen,val; for (tp = xcp->types, os = xcp->opts; tp->type != -1; tp++, os++) os->peer_value = tp->default_value; bp = state->bp; rlen = state->mlen; while (rlen > 0) { for (tp = xcp->types; tp->type != -1; tp++) if (tp->type == bp[0]) break; os = xcp->opts + (tp-xcp->types); 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->peer_value = val; rlen -= bp[1]; bp += bp[1]; }}/* * Perform RFC 1661 actions as indicated by state machine. */voiddispatch_action(struct ppp_state *state, struct ppp_xcp *xcp, enum xcp_action act){ unsigned char *bp; if (act == acNull) return; if (debugactions) printf("%s action %s (%d)\n",xcp->name,ac_str[(int)act],(int)act); switch (act) { case acNull: break; case acIrc: xcp->restart = state->phase == phTerminate ? MAX_TERMINATE : MAX_CONFIGURE; state->timeout_period = INITIAL_TIMEOUT; break; case acScr: if (xcp->restart > 0) { xcp->restart--; create_request(state,xcp); ppp_write(state,xcp,state->upbuf,state->up-state->upbuf); } xcp->restart_point = time(NULL)+state->timeout_period; break; case acTls: if (xcp == &state->xcps[XCP_IPCP]) send_event(state,&state->xcps[XCP_LCP],evOpen); else change_phase(state,phEstablish); break; case acTlf: if (xcp == &state->xcps[XCP_IPCP]) send_event(state,&state->xcps[XCP_LCP],evClose); else change_phase(state,phTerminate); break; case acStr: if (xcp->restart > 0) { xcp->restart--; bp = code_id(state,xcp,CODE_TERM_REQ); ppp_write(state,xcp,state->upbuf,bp-state->upbuf); } xcp->restart_point = time(NULL)+state->timeout_period; break; case acSta: bp = code_reply(state,xcp,CODE_TERM_ACK); ppp_write(state,xcp,state->upbuf,bp-state->upbuf); break; case acSca: copy_peer_values(state,xcp); state->inbuffer[4] = CODE_CONF_ACK; ppp_write(state,xcp,state->inbuffer, state->mlen+(state->bp-state->inbuffer)); break; case acScn: if (xcp->naks_sent++ >= MAX_FAILURE) state->upbuf[4] = CODE_CONF_REJ; case acScj: ppp_write(state,xcp,state->upbuf,state->up-state->upbuf); break; case acTld: if (xcp == &state->xcps[XCP_LCP]) change_phase(state,phTerminate); else printf("IPCP is now down!\n"); break; case acTlu: if (xcp == &state->xcps[XCP_LCP]) change_phase(state,phAuthenticate); else { struct option_state *os = find_option(xcp,3); struct in_addr addr; addr.s_addr = htonl(os->my_value); printf("IPCP is now up! Local address %s, ", inet_ntoa(addr)); addr.s_addr = htonl(os->peer_value); printf("remote %s\n",inet_ntoa(addr)); } xcp->restart = MAX_CONFIGURE; xcp->restart_point = 0; break; case acZrc: xcp->restart = 0; state->timeout_period = INITIAL_TIMEOUT; break; case acSer: state->inbuffer[4] = CODE_ECHO_REP; *(long *)(state->inbuffer+8) = htonl(state->mymagic); ppp_write(state,xcp,state->inbuffer, state->mlen+(state->bp-state->inbuffer)); break; }}/* * Issue event into XCP state machine -- go to next state and * invoke associated actions. */voidsend_event(struct ppp_state *state, struct ppp_xcp *xcp, enum ppp_event event){ const struct ppp_dispatch *dp; dp = &ppp_dispatch[(int)xcp->state][(int)event]; if (dp->next == stNoChange) { if (debugstates) printf("%s got illegal %s event (%d) in %s state (%d)\n\\t(RFC 1661 section 4.4)\n", xcp->name,ev_str[(int)event],event, st_str[(int)xcp->state],xcp->state); } else { if (debugstates) printf("%s got %s event (%d) in %s state (%d), next is %s state (%d)\n", xcp->name,ev_str[(int)event],event, st_str[(int)xcp->state],xcp->state, st_str[(int)dp->next],dp->next); xcp->state = dp->next; } dispatch_action(state,xcp,dp->act[0]); dispatch_action(state,xcp,dp->act[1]); dispatch_action(state,xcp,dp->act[2]);}/* * Change overall link phase. Central routine helps with * debugging. */voidchange_phase(struct ppp_state *state, enum ppp_phase phase){ if (debugphases) printf("Current PPP phase is %s, switching to %s\n", ph_str[(int)state->phase],ph_str[(int)phase]); switch (phase) { case phEstablish: if (state->phase == phDead) send_event(state,&state->xcps[XCP_LCP],evUp); break; case phAuthenticate: break; case phNetwork: if (state->phase == phAuthenticate) send_event(state,&state->xcps[XCP_IPCP],evUp); break; case phTerminate: send_event(state,&state->xcps[XCP_IPCP],evDown); break; case phDead: break; } state->phase = phase; if (phase == phAuthenticate) change_phase(state,phNetwork); /* XXX - no auth yet */}/* * Main loop. Handle timers and packet input. */voidread_packets(struct ppp_state *state){ unsigned char *bp; int retv,proto,i,rcvd_anything,alarm_running; struct timeval tv,*tvp; fd_set rfd; struct ppp_xcp *minsel; time_t now; rcvd_anything = 0; alarm_running = 0; for (;;) { /* Find earliest timer expiry. */ tvp = NULL; tv.tv_sec = 1000; tv.tv_usec = 0; minsel = NULL; now = time(NULL); for (i = 0; i < Dim(state->xcps); i++) if (state->xcps[i].restart_point != 0) { if (now > state->xcps[i].restart_point) { tv.tv_sec = 0; } else if (now+tv.tv_sec > state->xcps[i].restart_point) { tv.tv_sec = state->xcps[i].restart_point-now; } else continue; minsel = state->xcps+i; tvp = &tv; } /* If all NCPs up, then cancel main alarm. */ if (minsel == NULL) { alarm_running = 0; alarm(0); } else if (!alarm_running) { /* * If NCP negotiation (re)started, then set alarm. This * acts as an overall time limit on negotiation. If it * takes longer than MAX_WAIT, then give up. */ alarm_running = 1; alarm(MAX_WAIT); } if (debugtimer) { if (minsel == NULL) printf("No timers running.\n"); else printf("Timer set for %d seconds.\n",tv.tv_sec); } /* Wait for something. */ FD_ZERO(&rfd); FD_SET(state->sock,&rfd); retv = select(state->sock+1,&rfd,NULL,NULL,tvp); /* Check for timer events. */ if (retv >= 0 && minsel != NULL) { if (retv == 0 && state->timeout_period < MAX_TIMEOUT) state->timeout_period <<= 1; now = time(NULL); for (i = 0; i < Dim(state->xcps); i++) if (state->xcps[i].restart_point == 0) ; else if (now >= state->xcps[i].restart_point) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -