#include <sys/param.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include "alias_local.h"
struct grehdr
{
u_int16_t gh_flags;
u_int16_t gh_protocol;
u_int16_t gh_length;
u_int16_t gh_call_id;
u_int32_t gh_seq_no;
u_int32_t gh_ack_no;
};
typedef struct grehdr GreHdr;
#define PPTP_GRE_PROTO 0x880b
#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
#define PPTP_INIT_MASK 0xef7fffff
#define PPTP_MAGIC 0x1a2b3c4d
#define PPTP_CTRL_MSG_TYPE 1
enum {
PPTP_StartCtrlConnRequest = 1,
PPTP_StartCtrlConnReply = 2,
PPTP_StopCtrlConnRequest = 3,
PPTP_StopCtrlConnReply = 4,
PPTP_EchoRequest = 5,
PPTP_EchoReply = 6,
PPTP_OutCallRequest = 7,
PPTP_OutCallReply = 8,
PPTP_InCallRequest = 9,
PPTP_InCallReply = 10,
PPTP_InCallConn = 11,
PPTP_CallClearRequest = 12,
PPTP_CallDiscNotify = 13,
PPTP_WanErrorNotify = 14,
PPTP_SetLinkInfo = 15
};
struct pptpMsgHead {
u_int16_t length;
u_int16_t msgType;
u_int32_t magic;
u_int16_t type;
u_int16_t resv0;
};
typedef struct pptpMsgHead *PptpMsgHead;
struct pptpCodes {
u_int8_t resCode;
u_int8_t errCode;
};
typedef struct pptpCodes *PptpCode;
struct pptpCallIds {
u_int16_t cid1;
u_int16_t cid2;
};
typedef struct pptpCallIds *PptpCallId;
static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
void
AliasHandlePptpOut(struct ip *pip,
struct alias_link *link)
{
struct alias_link *pptp_link;
PptpCallId cptr;
PptpCode codes;
u_int16_t ctl_type;
struct tcphdr *tc;
if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
return;
switch (ctl_type) {
case PPTP_OutCallRequest:
case PPTP_OutCallReply:
case PPTP_InCallRequest:
case PPTP_InCallReply:
pptp_link = AddPptp(GetOriginalAddress(link), GetDestAddress(link),
GetAliasAddress(link), cptr->cid1);
break;
case PPTP_CallClearRequest:
case PPTP_CallDiscNotify:
pptp_link = FindPptpOutByCallId(GetOriginalAddress(link),
GetDestAddress(link),
cptr->cid1);
break;
default:
return;
}
if (pptp_link != NULL) {
int accumulate = cptr->cid1;
cptr->cid1 = GetAliasPort(pptp_link);
tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
accumulate -= cptr->cid1;
ADJUST_CHECKSUM(accumulate, tc->th_sum);
switch (ctl_type) {
case PPTP_OutCallReply:
case PPTP_InCallReply:
codes = (PptpCode)(cptr + 1);
if (codes->resCode == 1)
SetDestCallId(pptp_link,
cptr->cid2);
else
SetExpire(pptp_link, 0);
break;
case PPTP_CallDiscNotify:
SetExpire(pptp_link, 0);
break;
}
}
}
void
AliasHandlePptpIn(struct ip *pip,
struct alias_link *link)
{
struct alias_link *pptp_link;
PptpCallId cptr;
u_int16_t *pcall_id;
u_int16_t ctl_type;
struct tcphdr *tc;
if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
return;
switch (ctl_type)
{
case PPTP_InCallConn:
case PPTP_WanErrorNotify:
case PPTP_SetLinkInfo:
pcall_id = &cptr->cid1;
break;
case PPTP_OutCallReply:
case PPTP_InCallReply:
pcall_id = &cptr->cid2;
break;
case PPTP_CallDiscNotify:
pptp_link = FindPptpInByCallId(GetDestAddress(link),
GetAliasAddress(link),
cptr->cid1);
if (pptp_link != NULL)
SetExpire(pptp_link, 0);
return;
default:
return;
}
pptp_link = FindPptpInByPeerCallId(GetDestAddress(link),
GetAliasAddress(link),
*pcall_id);
if (pptp_link != NULL) {
int accumulate = *pcall_id;
*pcall_id = GetOriginalPort(pptp_link);
tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
accumulate -= *pcall_id;
ADJUST_CHECKSUM(accumulate, tc->th_sum);
if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) {
PptpCode codes = (PptpCode)(cptr + 1);
if (codes->resCode == 1)
SetDestCallId(pptp_link,
cptr->cid1);
else
SetExpire(pptp_link, 0);
}
}
}
static PptpCallId
AliasVerifyPptp(struct ip *pip, u_int16_t *ptype)
{
int hlen, tlen, dlen;
PptpMsgHead hptr;
struct tcphdr *tc;
tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
hlen = (pip->ip_hl + tc->th_off) << 2;
tlen = ntohs(pip->ip_len);
dlen = tlen - hlen;
if (dlen < (sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
return(NULL);
hptr = (PptpMsgHead)(((char *) pip) + hlen);
*ptype = ntohs(hptr->type);
if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
(ntohl(hptr->magic) != PPTP_MAGIC))
return(NULL);
if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
(dlen < sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
sizeof(struct pptpCodes)))
return (NULL);
else
return (PptpCallId)(hptr + 1);
}
int
AliasHandlePptpGreOut(struct ip *pip)
{
GreHdr *gr;
struct alias_link *link;
gr = (GreHdr *)((char *)pip + (pip->ip_hl << 2));
if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
return (-1);
link = FindPptpOutByPeerCallId(pip->ip_src, pip->ip_dst, gr->gh_call_id);
if (link != NULL) {
struct in_addr alias_addr = GetAliasAddress(link);
DifferentialChecksum(&pip->ip_sum,
(u_short *)&alias_addr,
(u_short *)&pip->ip_src,
2);
pip->ip_src = alias_addr;
}
return (0);
}
int
AliasHandlePptpGreIn(struct ip *pip)
{
GreHdr *gr;
struct alias_link *link;
gr = (GreHdr *)((char *)pip + (pip->ip_hl << 2));
if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
return (-1);
link = FindPptpInByPeerCallId(pip->ip_src, pip->ip_dst, gr->gh_call_id);
if (link != NULL) {
struct in_addr src_addr = GetOriginalAddress(link);
gr->gh_call_id = GetOriginalPort(link);
DifferentialChecksum(&pip->ip_sum,
(u_short *)&src_addr,
(u_short *)&pip->ip_dst,
2);
pip->ip_dst = src_addr;
}
return (0);
}