diff -uNr linux-2.2.2-clean/include/net/ip_masq_mod.h linux/include/net/ip_masq_mod.h --- linux-2.2.2-clean/include/net/ip_masq_mod.h Thu Jan 28 18:42:40 1999 +++ linux/include/net/ip_masq_mod.h Sun Feb 21 18:37:10 1999 @@ -37,11 +37,22 @@ struct ip_masq *); struct ip_masq * (*mmod_out_create) (const struct sk_buff *, const struct iphdr *, __u32); }; + +struct ip_masq_proto_mod { + struct ip_masq_proto_mod *next; /* next mod for addrs. lookups */ + __u16 protocol; + int (*masquerade) (struct sk_buff **skb_p, __u32 maddr); + int (*demasquerade) (struct sk_buff **skb_p); + atomic_t refcnt; +}; /* * Service routines (called from ip_masq.c) */ +int ip_masq_mod_init(void); +int ip_masquerade_proto(__u16 protocol, struct sk_buff **skb_ptr, __u32 maddr); +int ip_demasquerade_proto(__u16 protocol, struct sk_buff **skb_ptr); int ip_masq_mod_out_rule(const struct sk_buff *, const struct iphdr *); int ip_masq_mod_out_update(const struct sk_buff *, const struct iphdr *, struct ip_masq *ms); struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr); @@ -55,6 +66,8 @@ /* * ip_masq_mod registration functions */ +extern int register_ip_masq_proto_mod(struct ip_masq_proto_mod *mmod); +extern int unregister_ip_masq_proto_mod(struct ip_masq_proto_mod *mmod); extern int register_ip_masq_mod(struct ip_masq_mod *mmod); extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod); extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod); diff -uNr linux-2.2.2-clean/net/ipv4/Config.in linux/net/ipv4/Config.in --- linux-2.2.2-clean/net/ipv4/Config.in Mon Jan 18 22:26:22 1999 +++ linux/net/ipv4/Config.in Sun Feb 21 18:39:15 1999 @@ -39,6 +39,7 @@ bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY bool 'IP: masquerading' CONFIG_IP_MASQUERADE if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then + tristate 'IP: pptp masq support' CONFIG_IP_MASQUERADE_PPTP comment 'Protocol-specific masquerading support will be built as modules.' bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP comment 'Protocol-specific masquerading support will be built as modules.' diff -uNr linux-2.2.2-clean/net/ipv4/Makefile linux/net/ipv4/Makefile --- linux-2.2.2-clean/net/ipv4/Makefile Mon Jan 18 22:26:21 1999 +++ linux/net/ipv4/Makefile Sun Feb 21 18:41:30 1999 @@ -91,6 +91,14 @@ endif +ifeq ($(CONFIG_IP_MASQUERADE_PPTP),y) +IPV4_OBJS += ip_masq_pptp.o +else + ifeq ($(CONFIG_IP_MASQUERADE_PPTP),m) + M_OBJS += ip_masq_pptp.o + endif +endif + M_OBJS += ip_masq_user.o M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o diff -uNr linux-2.2.2-clean/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- linux-2.2.2-clean/net/ipv4/ip_masq.c Wed Jan 20 09:44:11 1999 +++ linux/net/ipv4/ip_masq.c Sun Feb 21 18:44:15 1999 @@ -1060,7 +1060,7 @@ doff = proto_doff(iph->protocol, h.raw, size); - if (doff <= 0) { + if (doff < 0) { /* * Output path: do not pass other IP protos nor * invalid packets. @@ -1113,6 +1113,8 @@ } break; default: + if (ip_masquerade_proto(iph->protocol, skb_p, maddr) == 1) + return 0; return -1; } /* @@ -1825,16 +1827,13 @@ doff = proto_doff(iph->protocol, h.raw, size); - switch (doff) { - case 0: - /* - * Input path: other IP protos Ok, will - * reach local sockets path. - */ - return 0; - case -1: - IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n"); - return -1; + if (doff == -1) { + /* + * Input path: other IP protos Ok, will + * reach local sockets path. + */ + IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n"); + return -1; } maddr = iph->daddr; @@ -1888,7 +1887,7 @@ } break; default: - return 0; + return ip_demasquerade_proto(iph->protocol, skb_p); } @@ -2378,6 +2377,7 @@ ip_mfw_init(); #endif ip_masq_app_init(); + ip_masq_mod_init(); return 0; } diff -uNr linux-2.2.2-clean/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c --- linux-2.2.2-clean/net/ipv4/ip_masq_mod.c Mon Jan 18 22:26:26 1999 +++ linux/net/ipv4/ip_masq_mod.c Sun Feb 21 18:45:45 1999 @@ -28,6 +28,8 @@ #include #endif +EXPORT_SYMBOL(register_ip_masq_proto_mod); +EXPORT_SYMBOL(unregister_ip_masq_proto_mod); EXPORT_SYMBOL(register_ip_masq_mod); EXPORT_SYMBOL(unregister_ip_masq_mod); EXPORT_SYMBOL(ip_masq_mod_lkp_link); @@ -38,6 +40,11 @@ #endif /* + * Base pointer for registered protocol modules + */ +struct ip_masq_proto_mod * ip_masq_proto_mod_base = NULL; + +/* * Base pointer for registered modules */ struct ip_masq_mod * ip_masq_mod_reg_base = NULL; @@ -321,4 +328,83 @@ return mmod->mmod_ctl(optname, mctl, optlen); #endif return ESRCH; +} + +int register_ip_masq_proto_mod(struct ip_masq_proto_mod *mod) +{ + if (!mod) { + IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n"); + return -EINVAL; + } + + mod->next = ip_masq_proto_mod_base; + ip_masq_proto_mod_base=mod; + + return 0; +} + +int unregister_ip_masq_proto_mod(struct ip_masq_proto_mod *mod) +{ + struct ip_masq_proto_mod **mod_p; + + if (!mod) { + IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n"); + return -EINVAL; + } + + /* + * Only allow unregistration if it is not referenced + */ + if (atomic_read(&mod->refcnt)) { + IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n", + atomic_read(&mod->refcnt)); + return -EINVAL; + } + + for (mod_p = &ip_masq_proto_mod_base; *mod_p ; mod_p = &(*mod_p)->next) { + if (mod == (*mod_p)) { + *mod_p = mod->next; + return 0; + } + } + + return -EINVAL; +} + +int ip_masquerade_proto(__u16 protocol, struct sk_buff **skb_ptr, __u32 maddr) +{ + struct ip_masq_proto_mod *mod; + int ret; + + for (mod = ip_masq_proto_mod_base; mod != NULL; mod = mod->next) { + if (mod->protocol == protocol) { + ret = mod->masquerade(skb_ptr, maddr); + if (ret == 1) + return ret; + } + } + return 0; +} + +int ip_demasquerade_proto(__u16 protocol, struct sk_buff **skb_ptr) +{ + struct ip_masq_proto_mod *mod; + int ret; + + for (mod = ip_masq_proto_mod_base; mod != NULL; mod = mod->next) { + if (mod->protocol == protocol) { + ret = mod->demasquerade(skb_ptr); + if (ret == 1) + return ret; + } + } + return 0; +} + +__initfunc(int ip_masq_mod_init(void)) +{ +#ifdef CONFIG_IP_MASQUERADE_PPTP + return ip_masq_pptp_init(); +#endif + return 0; } diff -uNr linux-2.2.2-clean/net/ipv4/ip_masq_pptp.c linux/net/ipv4/ip_masq_pptp.c --- linux-2.2.2-clean/net/ipv4/ip_masq_pptp.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/ip_masq_pptp.c Sun Feb 21 18:46:46 1999 @@ -0,0 +1,496 @@ +/* + * ip_masq_pptp.c + * + * Masquerading for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found on the Microsoft web site. + * + * Copyright (c) 1997-1998 Gordon Chaffee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG_CONFIG_IP_MASQUERADE_GRE 1 */ + +#define PPTP_GRE_VERSION 0x1 +#define PPTP_GRE_PROTOCOL 0x880B + +#define PPTP_GRE_FLAG_C 0x80 +#define PPTP_GRE_FLAG_R 0x40 +#define PPTP_GRE_FLAG_K 0x20 +#define PPTP_GRE_FLAG_S 0x10 +#define PPTP_GRE_FLAG_A 0x80 + +#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C) +#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R) +#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K) +#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S) +#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A) + +struct pptp_gre_hdr { + __u8 flags; /* bitfield */ + __u8 version; /* should be PPTP_GRE_VER (enhanced GRE) */ + __u16 protocol; /* should be PPTP_GRE_PROTO (ppp-encaps) */ + __u16 payload_len; /* size of ppp payload, not inc. gre header */ + __u16 call_id; /* peer's call_id for this session */ + __u32 seq; /* sequence number. Present if S==1 */ + __u32 ack; /* seq number of highest packet recieved by */ + /* sender in this session */ +}; + +#define PPTP_CONTROL_PACKET 1 +#define PPTP_MGMT_PACKET 2 +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d + +struct pptp_pkt_hdr { + __u16 packetLength; + __u16 packetType; + __u32 magicCookie; +}; + +/* PptpControlMessageType values */ +#define PPTP_START_SESSION_REQUEST 1 +#define PPTP_START_SESSION_REPLY 2 +#define PPTP_STOP_SESSION_REQUEST 3 +#define PPTP_STOP_SESSION_REPLY 4 +#define PPTP_ECHO_REQUEST 5 +#define PPTP_ECHO_REPLY 6 +#define PPTP_OUT_CALL_REQUEST 7 +#define PPTP_OUT_CALL_REPLY 8 +#define PPTP_IN_CALL_REQUEST 9 +#define PPTP_IN_CALL_REPLY 10 +#define PPTP_CALL_CLEAR_REQUEST 11 +#define PPTP_CALL_DISCONNECT_NOTIFY 12 +#define PPTP_CALL_ERROR_NOTIFY 13 +#define PPTP_WAN_ERROR_NOTIFY 14 +#define PPTP_SET_LINK_INFO 15 + +/* PptpGeneralError values */ +#define PPTP_ERROR_CODE_NONE 0 +#define PPTP_NOT_CONNECTED 1 +#define PPTP_BAD_FORMAT 2 +#define PPTP_BAD_VALUE 3 +#define PPTP_NO_RESOURCE 4 +#define PPTP_BAD_CALLID 5 +#define PPTP_REMOVE_DEVICE_ERROR 6 + +typedef struct { + __u16 messageType; + __u16 reserved; +} PptpControlHeader; + +/* FramingCapability Bitmap Values */ +#define PPTP_FRAME_CAP_ASYNC 0x1 +#define PPTP_FRAME_CAP_SYNC 0x2 + +/* BearerCapability Bitmap Values */ +#define PPTP_BEARER_CAP_ANALOG 0x1 +#define PPTP_BEARER_CAP_DIGITAL 0x2 + +typedef struct { + __u16 protocolVersion; + __u8 reserved1; + __u8 reserved2; + __u32 framingCapability; + __u32 bearerCapability; + __u16 maxChannels; + __u16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +} PptpStartSessionRequest; + +/* PptpStartSessionResultCode Values */ +#define PPTP_START_OK 1 +#define PPTP_START_GENERAL_ERROR 2 +#define PPTP_START_ALREADY_CONNECTED 3 +#define PPTP_START_NOT_AUTHORIZED 4 +#define PPTP_START_UNKNOWN_PROTOCOL 5 + +typedef struct { + __u16 protocolVersion; + __u8 resultCode; + __u8 generalErrorCode; + __u32 framingCapability; + __u32 bearerCapability; + __u16 maxChannels; + __u16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +} PptpStartSessionReply; + +/* PptpStopReasons */ +#define PPTP_STOP_NONE 1 +#define PPTP_STOP_PROTOCOL 2 +#define PPTP_STOP_LOCAL_SHUTDOWN 3 + +typedef struct { + __u8 reason; +} PptpStopSessionRequest; + +/* PptpStopSessionResultCode */ +#define PPTP_STOP_OK 1 +#define PPTP_STOP_GENERAL_ERROR 2 + +typedef struct { + __u8 resultCode; + __u8 generalErrorCode; +} PptpStopSessionReply; + +typedef struct { + __u32 identNumber; +} PptpEchoRequest; + +/* PptpEchoReplyResultCode */ +#define PPTP_ECHO_OK 1 +#define PPTP_ECHO_GENERAL_ERROR 2 + +typedef struct { + __u32 identNumber; + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved; +} PptpEchoReply; + +/* PptpFramingType */ +#define PPTP_ASYNC_FRAMING 1 +#define PPTP_SYNC_FRAMING 2 +#define PPTP_DONT_CARE_FRAMING 3 + +/* PptpCallBearerType */ +#define PPTP_ANALOG_TYPE 1 +#define PPTP_DIGITAL_TYPE 2 +#define PPTP_DONT_CARE_BEARER_TYPE 3 + +typedef struct { + __u16 callID; + __u16 callSerialNumber; + __u32 minBPS; + __u32 maxBPS; + __u32 bearerType; + __u32 framingType; + __u16 packetWindow; + __u16 packetProcDelay; + __u16 reserved1; + __u16 phoneNumberLength; + __u16 reserved2; + __u8 phoneNumber[64]; + __u8 subAddress[64]; +} PptpOutCallRequest; + +/* PptpCallResultCode */ +#define PPTP_OUTCALL_CONNECT 1 +#define PPTP_OUTCALL_GENERAL_ERROR 2 +#define PPTP_OUTCALL_NO_CARRIER 3 +#define PPTP_OUTCALL_BUSY 4 +#define PPTP_OUTCALL_NO_DIAL_TONE 5 +#define PPTP_OUTCALL_TIMEOUT 6 +#define PPTP_OUTCALL_DONT_ACCEPT 7 + +typedef struct { + __u16 callID; + __u16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 causeCode; + __u32 connectSpeed; + __u16 packetWindow; + __u16 packetProcDelay; + __u32 physChannelID; +} PptpOutCallReply; + +typedef struct { + __u16 callID; + __u16 callSerialNumber; + __u32 callBearerType; + __u32 physChannelID; + __u16 dialedNumberLength; + __u16 dialingNumberLength; + __u8 dialedNumber[64]; + __u8 dialingNumber[64]; + __u8 subAddress[64]; +} PptpInCallRequest; + +/* PptpInCallResultCode */ +#define PPTP_INCALL_ACCEPT 1 +#define PPTP_INCALL_GENERAL_ERROR 2 +#define PPTP_INCALL_DONT_ACCEPT 3 + +typedef struct { + __u16 callID; + __u16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 packetWindow; + __u16 packetProcDelay; + __u16 reserved; +} PptpInCallReply; + +typedef struct { + __u16 callID; + __u16 peersCallID; + __u32 connectSpeed; + __u16 packetWindow; + __u16 packetProcDelay; + __u32 callFramingType; +} PptpInCallConnected; + +typedef struct { + __u16 callID; + __u16 reserved; +} PptpClearCallRequest; + +/* PptpCallDisconnectCode */ +typedef struct { + __u16 callID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 causeCode; + __u16 reserved; + __u8 callStatistics[128]; +} PptpCallDisconnectNotify; + +typedef struct { + __u16 peersCallID; + __u16 reserved; + __u32 crcErrors; + __u32 framingErrors; + __u32 hardwareOverRuns; + __u32 bufferOverRuns; + __u32 timeoutErrors; + __u32 alignmentErrors; +} PptpWanErrorNotify; + +typedef struct { + __u16 peersCallID; + __u16 reserved; + __u32 sendAccm; + __u32 recvAccm; +} PptpSetLinkInfo; + + +/* + * If we handle the packet, return 1. If we do not, return 0. If there + * is some sort of error, return -1 + */ +static int masq_pptp(struct sk_buff **skb_ptr, __u32 maddr) +{ + struct sk_buff *skb=*skb_ptr; + struct iphdr *iph = skb->nh.iph; + struct ip_masq *ms; + struct pptp_gre_hdr *grehdr; + struct pptp_pkt_hdr *pkt_hdr; + int len; + int n; + +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + printk("Outgoing GRE %lX -> %lX\n", + ntohl(iph->saddr), ntohl(iph->daddr)); +#endif + + len = skb->len - iph->ihl*4; + if (len < 0) return 0; + + grehdr = (struct pptp_gre_hdr *) &(((char *)iph)[iph->ihl*4]); + n = sizeof(struct pptp_gre_hdr); + if (! PPTP_GRE_IS_S(grehdr->flags)) + n -= sizeof(grehdr->seq); + if (! PPTP_GRE_IS_A(grehdr->flags)) + n -= sizeof(grehdr->ack); + len -= n; + if (len < 0) return 0; +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + { + unsigned char *data = (unsigned char *) grehdr; + int i, j, max; + char buf[200]; + + data += n; + for (i = 0; i < len; i += 16) { + max = 16; + if (i + 16 > len) { + max = len - i; + } + for (j = 0; j < max; j++) { + sprintf(&buf[j*3], "%02x ", data[i+j]); + } + buf[j*3] = '\n'; + buf[j*3+1] = 0; + printk(buf); + } + } +#endif + + if ((grehdr->version & 0x7F) != PPTP_GRE_VERSION) return 0; + if (ntohs(grehdr->protocol) != PPTP_GRE_PROTOCOL) return 0; + +#if 0 /* Incorrect. Should be starting with a PptpStartSessionRequest */ + pkt_hdr = (struct pptp_pkt_hdr *) &(((char *) grehdr)[n]); + if (len < sizeof(struct pptp_pkt_hdr)) return 0; + if (ntohl(pkt_hdr->magicCookie) != PPTP_MAGIC_COOKIE) return 0; +#endif + /* + * Now hunt the list to see if we have an old entry + */ + + ms = ip_masq_out_get(iph->protocol, iph->saddr, 0, iph->daddr, 0); + + /* + * Nope, not found, create a new entry for it + */ + + if (ms==NULL) + { + ms = ip_masq_new(iph->protocol, maddr, 0, + iph->saddr, 0 /* grehdr->call_id */, + iph->daddr, 0, 0); +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + printk("Outgoing GRE %lX -> %lX: ms=%p\n", + ntohl(iph->saddr), ntohl(iph->daddr), ms); +#endif + if (ms == NULL) + return 0; + } + + /* + * Change the fragments origin + * Set iph addr from ip_masq obj. + */ + + iph->saddr = maddr; + /* grehdr->call_id = ms->mport; */ + + iph->check=0; + iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl); + + ip_send_check(iph); + +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + printk("O-routed from %lX\n",ntohl(ms->maddr)); +#endif + ip_masq_put(ms); + + return 1; +} + +/* + * If we handle the packet, return 1. If we do not, return 0. If there + * is some sort of error, return -1 + */ +static int demasq_pptp(struct sk_buff **skb_p) +{ + struct sk_buff *skb = *skb_p; + struct iphdr *iph = skb->nh.iph; + struct ip_masq *ms; + struct pptp_gre_hdr *grehdr; + struct pptp_pkt_hdr *pkt_hdr; + int len; + int n; + +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + printk("Incoming GRE %lX -> %lX\n", + ntohl(iph->saddr), ntohl(iph->daddr)); +#endif + + len = skb->len - iph->ihl*4; + if (len < 0) return 0; + + grehdr = (struct pptp_gre_hdr *) &(((char *)iph)[iph->ihl*4]); + n = sizeof(struct pptp_gre_hdr); + if (! PPTP_GRE_IS_S(grehdr->flags)) + n -= sizeof(grehdr->seq); + if (! PPTP_GRE_IS_A(grehdr->flags)) + n -= sizeof(grehdr->ack); + len -= n; + if (len < 0) return 0; + + if ((grehdr->version & 0x7F) != PPTP_GRE_VERSION) return 0; + if (ntohs(grehdr->protocol) != PPTP_GRE_PROTOCOL) return 0; + + /* + * reroute to original host if found... + */ + + ms = ip_masq_in_get(iph->protocol, iph->saddr, 0 /* grehdr->call_id */, + iph->daddr, 0); + + if (ms != NULL) + { + iph->daddr = ms->saddr; + + /* + * Adjust IP checksums. + */ + iph->check=0; + iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl); + ip_send_check(iph); +#ifdef DEBUG_CONFIG_IP_MASQUERADE_GRE + printk("I-routed GRE to %lX\n",ntohl(iph->daddr)); +#endif + ip_masq_put(ms); + + return 1; + } + + /* sorry, all this trouble for a no-hit :) */ + return 0; +} + +#define IPPROTO_GRE 47 + +struct ip_masq_proto_mod ip_gre_pptp_mod = { + NULL, IPPROTO_GRE, masq_pptp, demasq_pptp, ATOMIC_INIT(0) +}; + + +/* + * ip_masq_pptp initialization + */ + +__initfunc(int ip_masq_pptp_init(void)) +{ + return register_ip_masq_proto_mod(&ip_gre_pptp_mod); +} + +/* + * ip_masq_pptp fin. + */ + +int ip_masq_pptp_done(void) +{ + return unregister_ip_masq_proto_mod(&ip_gre_pptp_mod); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + if (ip_masq_pptp_init() != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + if (ip_masq_pptp_done() != 0) + printk("ip_masq_pptp: can't remove module"); +} + +#endif /* MODULE */ + +