📄 minimal-ppp.c
字号:
/* * A minimal implementation of PPP tunneled over UDP. This implements * just LCP and IPCP, and then only a subset of each of those. This * is not supported and probably shouldn't be used for much more than * simple experiments with PPP. If you need a real version of PPP, * see Paul Mackerras' ppp-2.3. If you do try to use this, don't say * I didn't warn you. * * This code may be used for any purpose as long as the author's * copyright is cited in any source code distributed. This code * is also available electronically from the author's web site. * * http://people.ne.mediaone.net/carlson/ppp * * http://www.workingcode.com/ppp * * Copyright 1997 by James Carlson and Working Code */#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <unistd.h>#include <strings.h>#include <time.h>#include <ctype.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#ifdef _AIX#include <sys/select.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <signal.h>#include <errno.h>#define MAX_TERMINATE 2#define MAX_CONFIGURE 10#define MAX_FAILURE 5#define INITIAL_TIMEOUT 2#define MAX_TIMEOUT 8#define DEFAULT_MRU 1500#define MAX_WAIT 40 /* Maximum wait time for PPP to come up. */#define Dim(x) (sizeof(x)/sizeof(*(x)))int remote_ip_base = 0x0A000000;int remote_ip_mask = 0xFF000000;char *myname;int showpackets = 0, debugphases = 0, debugstates = 0, debugactions = 0;int showraw = 0, debugtimer = 0;voidusage(void){ fprintf(stderr,"\nUsage:\n\t%s [-adpstv] <peer-IP> [<peer-port> [<local-port>]]\n\n", myname); fprintf(stderr,"\t-a\tShow state machine actions\n"); fprintf(stderr,"\t-d\tShow raw data\n"); fprintf(stderr,"\t-p\tShow link phases\n"); fprintf(stderr,"\t-s\tShow XCP states\n"); fprintf(stderr,"\t-t\tShow timer actions\n"); fprintf(stderr,"\t-v\tShow negotiation packets\n"); exit(1);}/* Look up UDP port number. */intresolve_port(char *port_name){ struct servent *sp; char *cp; int pnum; if (port_name != NULL) { sp = getservbyname(port_name,"udp"); if (sp == NULL) { pnum = strtol(port_name,&cp,0); if (pnum <= 0 || pnum > 65535 || port_name == cp || *cp != '\0') { fprintf(stderr,"Illegal port name/number '%s'\n",port_name); return -1; } pnum = htons(pnum); } else pnum = sp->s_port; } else pnum = htons(5001); return pnum;}/* Set up connected UDP socket. */intset_up_tunnel(char **argv){ struct sockaddr_in sin,bsin; struct hostent *hp; int sock = -1,nlen; char *host_name; host_name = *argv++; if (host_name == NULL) { fprintf(stderr,"Must specify a peer name or IP address.\n"); return -1; } memset(&sin,0,sizeof(sin)); memset(&bsin,0,sizeof(bsin)); sin.sin_port = resolve_port(*argv); bsin.sin_port = resolve_port(*argv?argv[1]:NULL); hp = gethostbyname(host_name); if (hp == NULL) { sin.sin_family = AF_INET; if ((sin.sin_addr.s_addr = inet_addr(host_name)) == (unsigned long)-1) { (void)fprintf(stderr, "%s: Host \"%s\" not found.\n", myname,host_name); return -1; } } else { memcpy((char *)&sin.sin_addr,(char *)hp->h_addr,hp->h_length); sin.sin_family = hp->h_addrtype; } sock = socket(AF_INET,SOCK_DGRAM,0); if (sock < 0) { perror("socket"); return -1; } nlen = 1; if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&nlen,sizeof(nlen)) == -1) { perror("setsockopt"); close(sock); return -1; } bsin.sin_family = AF_INET; bsin.sin_addr.s_addr = INADDR_ANY; if (bind(sock,(struct sockaddr *)&bsin,sizeof(bsin)) == -1) { perror("bind"); close(sock); return -1; } nlen = sizeof(bsin); if (getsockname(sock,(struct sockaddr *)&bsin,&nlen) == -1) { perror("getsockname"); close(sock); return -1; } if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) == -1) { perror("connect"); close(sock); return -1; } printf("Tunnel from %s:%d to ",inet_ntoa(bsin.sin_addr), ntohs(bsin.sin_port)); printf("%s:%d.\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port)); return sock;}/* Handle fatal negotiation timeout. */voidalarm_handle(dummy)int dummy;{ fprintf(stderr,"PPP failed to negotiate in prescribed time; shutting down.\n"); exit(1);}/* Standard link phases */enum ppp_phase { phDead, phEstablish, phAuthenticate, phNetwork, phTerminate};const char *ph_str[] = { "Dead", "Establish", "Authenticate", "Network", "Terminate"};/* Standard set of events */enum ppp_event { evUp = 0, evDown, evOpen, evClose, evTOp, evTOm, evRCRp, evRCRm, evRCA, evRCN, evRTR, evRTA, evRUC, evRXJp, evRXJm, evRXR};const char *ev_str[] = { "Up", "Down", "Open", "Close", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN", "RTR", "RTA", "RUC", "RXJ+", "RXJ-", "RXR"};/* Standard negotiation states */enum xcp_state { stInitial = 0, stStarting, stClosed, stStopped, stClosing, stStopping, stReqSent, stAckRcvd, stAckSent, stOpened, stNoChange};const char *st_str[] = { "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", "No-Change"};/* Standard set of actions */enum xcp_action { acNull, acIrc, acScr, acTls, acTlf, acStr, acSta, acSca, acScn, acScj, acTld, acTlu, acZrc, acSer};const char *ac_str[] = { "Null", "irc", "scr", "tls", "tlf", "str", "sta", "sca", "scn", "scj", "tld", "tlu", "zrc", "ser"};/* Dispatch table from RFC 1661 */const struct ppp_dispatch { enum xcp_state next; enum xcp_action act[3];} ppp_dispatch[10][16] = { { /* stInitial */ /* evUp */ { stClosed, { acNull, acNull, acNull } }, /* evDown */ { stNoChange, { acNull, acNull, acNull } }, /* evOpen */ { stStarting, { acTls, acNull, acNull } }, /* evClose */ { stClosed, { acNull, acNull, acNull } }, /* evTOp */ { stNoChange, { acNull, acNull, acNull } }, /* evTOm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRp */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCA */ { stNoChange, { acNull, acNull, acNull } }, /* evRCN */ { stNoChange, { acNull, acNull, acNull } }, /* evRTR */ { stNoChange, { acNull, acNull, acNull } }, /* evRTA */ { stNoChange, { acNull, acNull, acNull } }, /* evRUC */ { stNoChange, { acNull, acNull, acNull } }, /* evRXJp */ { stNoChange, { acNull, acNull, acNull } }, /* evRXJm */ { stNoChange, { acNull, acNull, acNull } }, /* evRXR */ { stNoChange, { acNull, acNull, acNull } }, }, { /* stStarting */ /* evUp */ { stReqSent, { acIrc, acScr, acNull } }, /* evDown */ { stNoChange, { acNull, acNull, acNull } }, /* evOpen */ { stStarting, { acNull, acNull, acNull } }, /* evClose */ { stInitial, { acTlf, acNull, acNull } }, /* evTOp */ { stNoChange, { acNull, acNull, acNull } }, /* evTOm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRp */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCA */ { stNoChange, { acNull, acNull, acNull } }, /* evRCN */ { stNoChange, { acNull, acNull, acNull } }, /* evRTR */ { stNoChange, { acNull, acNull, acNull } }, /* evRTA */ { stNoChange, { acNull, acNull, acNull } }, /* evRUC */ { stNoChange, { acNull, acNull, acNull } }, /* evRXJp */ { stNoChange, { acNull, acNull, acNull } }, /* evRXJm */ { stNoChange, { acNull, acNull, acNull } }, /* evRXR */ { stNoChange, { acNull, acNull, acNull } }, }, { /* stClosed */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stInitial, { acNull, acNull, acNull } }, /* evOpen */ { stReqSent, { acIrc, acScr, acNull } }, /* evClose */ { stClosed, { acNull, acNull, acNull } }, /* evTOp */ { stNoChange, { acNull, acNull, acNull } }, /* evTOm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRp */ { stClosed, { acSta, acNull, acNull } }, /* evRCRm */ { stClosed, { acSta, acNull, acNull } }, /* evRCA */ { stClosed, { acSta, acNull, acNull } }, /* evRCN */ { stClosed, { acSta, acNull, acNull } }, /* evRTR */ { stClosed, { acSta, acNull, acNull } }, /* evRTA */ { stClosed, { acNull, acNull, acNull } }, /* evRUC */ { stClosed, { acScj, acNull, acNull } }, /* evRXJp */ { stClosed, { acNull, acNull, acNull } }, /* evRXJm */ { stClosed, { acTlf, acNull, acNull } }, /* evRXR */ { stClosed, { acNull, acNull, acNull } }, }, { /* stStopped */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stStarting, { acTls, acNull, acNull } }, /* evOpen */ { stStopped, { acNull, acNull, acNull } }, /* evClose */ { stClosed, { acNull, acNull, acNull } }, /* evTOp */ { stNoChange, { acNull, acNull, acNull } }, /* evTOm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRp */ { stAckSent, { acIrc, acScr, acSca } }, /* evRCRm */ { stReqSent, { acIrc, acScr, acScn } }, /* evRCA */ { stStopped, { acSta, acNull, acNull } }, /* evRCN */ { stStopped, { acSta, acNull, acNull } }, /* evRTR */ { stStopped, { acSta, acNull, acNull } }, /* evRTA */ { stStopped, { acNull, acNull, acNull } }, /* evRUC */ { stStopped, { acScj, acNull, acNull } }, /* evRXJp */ { stStopped, { acNull, acNull, acNull } }, /* evRXJm */ { stStopped, { acTlf, acNull, acNull } }, /* evRXR */ { stStopped, { acNull, acNull, acNull } }, }, { /* stClosing */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stInitial, { acNull, acNull, acNull } }, /* evOpen */ { stStopping, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acNull, acNull, acNull } }, /* evTOp */ { stClosing, { acStr, acNull, acNull } }, /* evTOm */ { stClosed, { acTlf, acNull, acNull } }, /* evRCRp */ { stClosing, { acNull, acNull, acNull } }, /* evRCRm */ { stClosing, { acNull, acNull, acNull } }, /* evRCA */ { stClosing, { acNull, acNull, acNull } }, /* evRCN */ { stClosing, { acNull, acNull, acNull } }, /* evRTR */ { stClosing, { acSta, acNull, acNull } }, /* evRTA */ { stClosed, { acTlf, acNull, acNull } }, /* evRUC */ { stClosing, { acScj, acNull, acNull } }, /* evRXJp */ { stClosing, { acNull, acNull, acNull } }, /* evRXJm */ { stClosed, { acTlf, acNull, acNull } }, /* evRXR */ { stClosing, { acNull, acNull, acNull } }, }, { /* stStopping */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stInitial, { acNull, acNull, acNull } }, /* evOpen */ { stStopping, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acNull, acNull, acNull } }, /* evTOp */ { stStopping, { acStr, acNull, acNull } }, /* evTOm */ { stStopped, { acTlf, acNull, acNull } }, /* evRCRp */ { stStopping, { acNull, acNull, acNull } }, /* evRCRm */ { stStopping, { acNull, acNull, acNull } }, /* evRCA */ { stStopping, { acNull, acNull, acNull } }, /* evRCN */ { stStopping, { acNull, acNull, acNull } }, /* evRTR */ { stStopping, { acSta, acNull, acNull } }, /* evRTA */ { stStopped, { acTlf, acNull, acNull } }, /* evRUC */ { stStopping, { acScj, acNull, acNull } }, /* evRXJp */ { stStopping, { acNull, acNull, acNull } }, /* evRXJm */ { stStopped, { acTlf, acNull, acNull } }, /* evRXR */ { stStopping, { acNull, acNull, acNull } }, }, { /* stReqSent */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stStarting, { acNull, acNull, acNull } }, /* evOpen */ { stReqSent, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acIrc, acStr, acNull } }, /* evTOp */ { stReqSent, { acScr, acNull, acNull } }, /* evTOm */ { stStopped, { acTlf, acNull, acNull } }, /* evRCRp */ { stAckSent, { acSca, acNull, acNull } }, /* evRCRm */ { stReqSent, { acScn, acNull, acNull } }, /* evRCA */ { stAckRcvd, { acIrc, acNull, acNull } }, /* evRCN */ { stReqSent, { acIrc, acScr, acNull } }, /* evRTR */ { stReqSent, { acSta, acNull, acNull } }, /* evRTA */ { stReqSent, { acNull, acNull, acNull } }, /* evRUC */ { stReqSent, { acScj, acNull, acNull } }, /* evRXJp */ { stReqSent, { acNull, acNull, acNull } }, /* evRXJm */ { stStopped, { acTlf, acNull, acNull } }, /* evRXR */ { stReqSent, { acNull, acNull, acNull } }, }, { /* stAckRcvd */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stStarting, { acNull, acNull, acNull } }, /* evOpen */ { stAckRcvd, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acIrc, acStr, acNull } }, /* evTOp */ { stReqSent, { acScr, acNull, acNull } }, /* evTOm */ { stStopped, { acTlf, acNull, acNull } }, /* evRCRp */ { stOpened, { acSca, acTlu, acNull } }, /* evRCRm */ { stAckRcvd, { acScn, acNull, acNull } }, /* evRCA */ { stReqSent, { acScr, acNull, acNull } }, /* evRCN */ { stReqSent, { acScr, acNull, acNull } }, /* evRTR */ { stReqSent, { acSta, acNull, acNull } }, /* evRTA */ { stReqSent, { acNull, acNull, acNull } }, /* evRUC */ { stAckRcvd, { acScj, acNull, acNull } }, /* evRXJp */ { stReqSent, { acNull, acNull, acNull } }, /* evRXJm */ { stStopped, { acTlf, acNull, acNull } }, /* evRXR */ { stAckRcvd, { acNull, acNull, acNull } }, }, { /* stAckSent */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stStarting, { acNull, acNull, acNull } }, /* evOpen */ { stAckSent, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acIrc, acStr, acNull } }, /* evTOp */ { stAckSent, { acScr, acNull, acNull } }, /* evTOm */ { stStopped, { acTlf, acNull, acNull } }, /* evRCRp */ { stAckSent, { acSca, acNull, acNull } }, /* evRCRm */ { stReqSent, { acScn, acNull, acNull } }, /* evRCA */ { stOpened, { acIrc, acTlu, acNull } }, /* evRCN */ { stAckSent, { acIrc, acScr, acNull } }, /* evRTR */ { stReqSent, { acSta, acNull, acNull } }, /* evRTA */ { stAckSent, { acNull, acNull, acNull } }, /* evRUC */ { stAckSent, { acScj, acNull, acNull } }, /* evRXJp */ { stAckSent, { acNull, acNull, acNull } }, /* evRXJm */ { stStopped, { acTlf, acNull, acNull } }, /* evRXR */ { stAckSent, { acNull, acNull, acNull } }, }, { /* stOpened */ /* evUp */ { stNoChange, { acNull, acNull, acNull } }, /* evDown */ { stStarting, { acTld, acNull, acNull } }, /* evOpen */ { stOpened, { acNull, acNull, acNull } }, /* evClose */ { stClosing, { acTld, acIrc, acStr } }, /* evTOp */ { stNoChange, { acNull, acNull, acNull } }, /* evTOm */ { stNoChange, { acNull, acNull, acNull } }, /* evRCRp */ { stAckSent, { acTld, acScr, acSca } }, /* evRCRm */ { stReqSent, { acTld, acScr, acScn } }, /* evRCA */ { stReqSent, { acTld, acScr, acNull } }, /* evRCN */ { stReqSent, { acTld, acScr, acNull } }, /* evRTR */ { stStopping, { acTld, acZrc, acSta } }, /* evRTA */ { stReqSent, { acTld, acScr, acNull } }, /* evRUC */ { stOpened, { acScj, acNull, acNull } }, /* evRXJp */ { stOpened, { acNull, acNull, acNull } }, /* evRXJm */ { stStopping, { acTld, acIrc, acStr } }, /* evRXR */ { stOpened, { acSer, acNull, acNull } }, }};/* Standard message code numbers */#define CODE_CONF_REQ 1#define CODE_CONF_ACK 2#define CODE_CONF_NAK 3#define CODE_CONF_REJ 4#define CODE_TERM_REQ 5#define CODE_TERM_ACK 6#define CODE_CODE_REJ 7#define CODE_PROTO_REJ 8#define CODE_ECHO_REQ 9#define CODE_ECHO_REP 10#define CODE_DISCARD_REQ 11const char *code_str[] = { "Vendor", "Configure-Request", "Configure-Ack", "Configure-Nak", "Configure-Reject", "Terminate-Request", "Terminate-Ack", "Code-Reject", "Protocol-Reject", "Echo-Request", "Echo-Reply", "Discard-Request"};#define PROT_LCP 0xC021#define PROT_IPCP 0x8021struct ppp_xcp;struct ppp_state;/* Basic information about an option. */struct xcp_type { const char *name; /* Printable name */ short type; /* option number (-1 to end) */ short flag; /* set to ignore default value */ unsigned char minlen; /* minimum overall length */ unsigned char maxlen; /* maximum overall length */ int default_value; /* default */ void (*validate_req)(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len); void (*validate_nak)(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len); void (*show)(const struct ppp_state *state, const struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len);};const struct xcp_type lcp_types[] = { { NULL, -1, 0, 0, 0, 0, NULL, NULL, NULL }};void ipcp_addr_req(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len);void ipcp_addr_nak(struct ppp_state *state, struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len);void ipcp_addr_show(const struct ppp_state *state, const struct ppp_xcp *xcp, const struct xcp_type *tp, const unsigned char *buf, int len);const struct xcp_type ipcp_types[] = { { "IP-Address", 3, 1, 6, 6, 0, ipcp_addr_req, ipcp_addr_nak, ipcp_addr_show }, { NULL, -1, 0, 0, 0, 0, NULL, NULL, NULL }};struct option_state { int my_value; /* sent in Configure-Request */ int peer_value; /* last received */ enum { osUsable, osUnusable } state; /* flag for rejects */};struct ppp_xcp { const char *name; /* name of control protocol */ enum xcp_state state; /* state machine */ int restart; /* standard restart count */ time_t restart_point; /* standard restart timer */ int naks_sent; /* consecutive naks sent */ void (*deliver)(struct ppp_state *state, /* handler */ struct ppp_xcp *xcp); const struct xcp_type *types; /* option types supported here */ struct option_state *opts; /* current negotiation state */ unsigned short proto; /* PPP protocol ID */ unsigned char ident; /* current ID number */};enum parse_state { psOK, psNak, psRej, psBad };struct ppp_state { enum ppp_phase phase; /* link phase */ enum parse_state parse_state; /* request parsing state */ int sock; /* connection to physical layer */ int timeout_period; /* value for restart timer */ int mlen; /* packet length */ unsigned long mymagic,hismagic; /* magic numbers (for echo) */ unsigned char *bp,*up; /* pointers to packet buffers */ struct ppp_xcp xcps[2]; /* installed XCPs */ unsigned char inbuffer[1600],upbuf[1500];};#define XCP_LCP 0#define XCP_IPCP 1void send_event(struct ppp_state *state, struct ppp_xcp *xcp, enum ppp_event event);void change_phase(struct ppp_state *state, enum ppp_phase phase);/* Display contents of buffer */voidbuffer_print(const char *verb, const unsigned char *buf, int len){ int i,j; struct tm *tm; time_t now; now = time(NULL); tm = localtime(&now); printf("%02d:%02d %s %d bytes:\n",tm->tm_min,tm->tm_sec,verb,len); for (i = 0; i < len; i += 16) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -