diff -urN linux-2.1.105-clean/include/net/ip_masq_mod.h linux/include/net/ip_masq_mod.h --- linux-2.1.105-clean/include/net/ip_masq_mod.h Wed Dec 10 09:45:16 1997 +++ linux/include/net/ip_masq_mod.h Sun Jun 7 17:11:38 1998 @@ -38,9 +38,20 @@ struct ip_masq * (*mmod_out_create) (struct iphdr *, __u16 *, __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(struct iphdr *iph, __u16 *portp); int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms); struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr); @@ -54,6 +65,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 -urN linux-2.1.105-clean/net/ipv4/Config.in linux/net/ipv4/Config.in --- linux-2.1.105-clean/net/ipv4/Config.in Mon May 25 14:08:51 1998 +++ linux/net/ipv4/Config.in Mon Jun 8 00:53:42 1998 @@ -38,6 +38,7 @@ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then 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 -urN linux-2.1.105-clean/net/ipv4/Makefile linux/net/ipv4/Makefile --- linux-2.1.105-clean/net/ipv4/Makefile Mon May 25 14:08:51 1998 +++ linux/net/ipv4/Makefile Sun Jun 7 16:29:35 1998 @@ -78,6 +78,14 @@ endif 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_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o endif diff -urN linux-2.1.105-clean/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- linux-2.1.105-clean/net/ipv4/ip_masq.c Mon Apr 6 14:13:46 1998 +++ linux/net/ipv4/ip_masq.c Sun Jun 7 16:16:40 1998 @@ -911,11 +911,16 @@ * We may need to consider masq-ing some ICMP related to masq-ed protocols */ + + if (iph->protocol==IPPROTO_ICMP) return (ip_fw_masq_icmp(skb_ptr, maddr)); - if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) { + if (ip_masquerade_proto(iph->protocol, skb_ptr, maddr) == 1) + return 0; return -1; + } /* * Now hunt the list to see if we have an old entry @@ -1537,7 +1542,7 @@ } break; default: - return 0; + return ip_demasquerade_proto(iph->protocol, skb_p); } @@ -1851,6 +1856,6 @@ ip_portfw_init(); #endif ip_masq_app_init(); - + ip_masq_mod_init(); return 0; } diff -urN linux-2.1.105-clean/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c --- linux-2.1.105-clean/net/ipv4/ip_masq_mod.c Mon Apr 6 14:14:08 1998 +++ linux/net/ipv4/ip_masq_mod.c Sun Jun 7 16:39:47 1998 @@ -26,12 +26,19 @@ #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); EXPORT_SYMBOL(ip_masq_mod_lkp_unlink); /* + * 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; @@ -313,4 +320,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 -urN linux-2.1.105-clean/net/ipv4/ip_masq_pptp.c linux/net/ipv4/ip_masq_pptp.c --- linux-2.1.105-clean/net/ipv4/ip_masq_pptp.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/ip_masq_pptp.c Mon Jun 8 03:37:11 1998 @@ -0,0 +1,493 @@ +/* + * 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 + + 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 + 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 */ + +