#if HAVE_CONFIG_H #include #endif #include "pptpd.h" #include //#define PPTP_LINUXKLIENT #define MARINGOTKA #undef DEBUG_GRE_SND #undef DEBUG_GRE_RCV int gre_flush_out(struct control_struct * ctrl); int do_gre_packet(struct control_struct * ctrl, struct pptp_gre_header *g); int gre_init(struct control_struct * ctrl) { int i; if (ctrl->gre_fd >= 0) return 0; i = socket(PF_INET, SOCK_RAW, PPTP_PROTO); if (i == -1) { LOG("cannot create GRE socket: %s", strerror(errno)); return -1; } if (bind(i, (struct sockaddr *)&(ctrl->addr_local), sizeof(ctrl->addr_local)) == -1) { LOG("cannot bind GRE socket"); close(i); return -1; } if (connect(i, (struct sockaddr *)&(ctrl->addr_remote), sizeof(ctrl->addr_remote)) == -1) { LOG("cannot connect GRE socket"); close(i); return -1; } ctrl->gre_fd = i; LOG("Started DATA connection"); return 0; } void gre_set_timeout( struct control_struct *ctrl ) { gettimeofday(&(ctrl->gre_tv),NULL); TV_ADD((ctrl->gre_tv),(ctrl->gre_dtv)); } #define nSEQ(g) ( PPTP_GRE_IS_S((g)->flags) ? ((u_int32_t*)(&((g)[1])))[0] : 0 ) #define nACK(g) ( PPTP_GRE_IS_A((g)->ver) ? (PPTP_GRE_IS_S((g)->flags) ? ((u_int32_t*)(&((g)[1])))[1] : ((u_int32_t*)(&((g)[1])))[0] ) : 0 ) #define PAYLOAD(g) ( PPTP_GRE_IS_A((g)->ver) ? (PPTP_GRE_IS_S((g)->flags) ? (char*)(&(((u_int32_t*)(&((g)[1])))[2])) : (char*)(&(((u_int32_t*)(&((g)[1])))[1])) ) : (PPTP_GRE_IS_S((g)->flags) ? (char*)(&(((u_int32_t*)(&((g)[1])))[1])) : (char*)(&(((u_int32_t*)(&((g)[1])))[0])) ) ) #define SEQ(g) ntohl(nSEQ(g)) #define ACK(g) ntohl(nACK(g)) int gre_flush_in( struct control_struct * ctrl, u_int32_t ack ) { int i,r=0; while(ctrl->in_ack<=ack) { for(i=0;iin_window[i]!=NULL ) { if( SEQ(ctrl->in_window[i])==ctrl->in_ack ) { do_gre_packet(ctrl,ctrl->in_window[i]); free(ctrl->in_window[i]); ctrl->in_window[i]=NULL; r++; ctrl->in_ack++; continue; } else if( SEQ(ctrl->in_window[i])in_ack ) { free(ctrl->in_window[i]); ctrl->in_window[i]=NULL; } } } break; } return(r); } int do_gre_packet(struct control_struct * ctrl, struct pptp_gre_header *g) { // int i, j; // char buf2[6*GREFRAME_MAX], *p; struct ppp_struct *ppp; for(ppp=ctrl->ppp;ppp!=NULL && ppp->call_id!=g->call_id;) { LOG("known ppp id pair %x : %x",ppp->call_id,ppp->peers_call_id); ppp=ppp->next; } if( ppp==NULL ) { LOG("unexpected call_id %x",g->call_id); return(0); } return( send_ppp_packet(ctrl,ppp,PAYLOAD(g),ntohs(g->payload_len)) ); } int do_send_gre_packet(struct control_struct * ctrl, struct pptp_gre_header *g); int read_gre_packet(struct control_struct * ctrl) { int i, j, size; char buf[GREFRAME_MAX]; struct pptp_gre_header *g; u_int32_t seq,n,ack; int r=0; size = read(ctrl->gre_fd, buf, sizeof(buf)); if (size<=0) { LOG("GRE connection is closed"); return -1; } j= 4*(unsigned int)(((struct ip*)buf)->ip_hl); if( sizever&0x07)!=PPTP_GRE_VER || ntohs(g->protocol)!=PPTP_GRE_PROTO ) { LOG("invalid gre protocol"); return -1; } if( PPTP_GRE_IS_S(g->flags) ) { seq=SEQ(g); #ifndef DONT_HAVE_ACK_HACK if( seq == ctrl->in_ack ) #else if( seq == 0 ) #endif { r=do_gre_packet(ctrl,g); ctrl->in_ack++; if( seq > ctrl->in_seq ) ctrl->in_seq=seq; } else if( seq > ctrl->in_ack ) { if( seq > ctrl->in_seq ) { ctrl->in_seq=seq; n=ctrl->in_seq - ctrl->in_window_size; gre_flush_in(ctrl,n); } for(i=0;iin_window[i]==NULL) { if( (ctrl->in_window[i]=malloc(size)) ) memcpy(ctrl->in_window[i],g,size); } } } #ifndef DONT_HAVE_ACK_HACK while( gre_flush_in(ctrl,ctrl->in_ack) ); #endif } ack=ACK(g); if( ctrl->out_ack < ack ) { ctrl->out_ack = ack; gre_flush_out(ctrl); gre_set_timeout(ctrl); } do_send_gre_packet(ctrl,NULL); return( r ); } int gre_timeout(struct control_struct * ctrl) { ctrl->out_ack = ctrl->out_seq; gre_flush_out(ctrl); return(0); } int do_send_gre_packet(struct control_struct * ctrl, struct pptp_gre_header *g) { int len; char buf[GREFRAME_MAX]; struct ip *ip; int p; ip=(struct ip*)buf; if( g!=NULL ) { g->flags=PPTP_GRE_FLAG_K|PPTP_GRE_FLAG_S; g->ver=PPTP_GRE_VER; g->protocol=htons(PPTP_GRE_PROTO); memcpy(buf+sizeof(struct ip),g,sizeof(struct pptp_gre_header)+4); p=sizeof(struct ip)+sizeof(struct pptp_gre_header)+4; len=ntohs(g->payload_len)+sizeof(struct pptp_gre_header)+4+sizeof(struct ip); } else { struct pptp_gre_header gg; #ifndef DONT_GIVE_ACK_HACK if( ctrl->in_ack==ctrl->in_pack ) #endif return(0); gg.flags=PPTP_GRE_FLAG_K; gg.ver=PPTP_GRE_VER; gg.protocol=htons(PPTP_GRE_PROTO); gg.payload_len=htons(0); gg.call_id=0; /* K maybe 0 */ memcpy(buf+sizeof(struct ip),&gg,sizeof(struct pptp_gre_header)); p=sizeof(struct ip)+sizeof(struct pptp_gre_header); len=sizeof(struct pptp_gre_header)+sizeof(struct ip); } #ifndef DONT_GIVE_ACK_HACK if( ctrl->in_ack!=ctrl->in_pack ) { ctrl->in_pack=ctrl->in_ack; ((u_int32_t*)(buf+p))[0]=htonl(ctrl->in_ack-1); p+=4; len+=4; ((struct pptp_gre_header*)(buf+sizeof(struct ip)))->ver|=PPTP_GRE_FLAG_A; } #endif if( g!=NULL ) memcpy(buf+p,(char *)g+sizeof(struct pptp_gre_header)+4,ntohs(g->payload_len)); /* pro-forma ip header filling */ ip->ip_v = 4; ip->ip_hl = 5; ip->ip_tos = 0; ip->ip_len = htons(len); ip->ip_id = 0; ip->ip_off = 0; ip->ip_ttl = 255; ip->ip_p = 0x2f; /* GRE proto */ ip->ip_sum = 0; memcpy(&ip->ip_src, &(ctrl->addr_local.sin_addr.s_addr), sizeof(ip->ip_src)); memcpy(&ip->ip_dst, &(ctrl->addr_remote.sin_addr.s_addr), sizeof(ip->ip_dst)); // write(ctrl->gre_fd,buf,len); write(ctrl->gre_fd,buf+sizeof(struct ip),len-sizeof(struct ip)); #ifdef DEBUG_GRE_SND { int ww; printf("GRE SND: "); for(ww=0; wwout_ack+1;aout_ack+1+ctrl->out_window_size;) { for(i=0;iout_window[i]!=NULL) { if( SEQ(ctrl->out_window[i])==a ) do_send_gre_packet(ctrl,ctrl->out_window[i]); if( SEQ(ctrl->out_window[i])<=a ) { free(ctrl->out_window[i]); ctrl->out_window[i]=NULL; } } } a++; } return(0); } int send_gre_packet(struct control_struct * ctrl, struct ppp_struct *ppp, char *data, int len) { int i, size; char buf[GREFRAME_MAX]; struct pptp_gre_header *g; #ifndef DONT_HAVE_OUT_WINDOW if( ctrl->out_seq - ctrl->out_ack < ctrl->out_window_size+1 ) #else if(1) #endif { size=len+sizeof(struct pptp_gre_header)+4; g=(struct pptp_gre_header *)buf; g->flags=PPTP_GRE_FLAG_K|PPTP_GRE_FLAG_S; g->ver=PPTP_GRE_VER; g->payload_len=htons(len); g->call_id=ppp->peers_call_id; ((u_int32_t*)(&(g[1])))[0]=htonl(ctrl->out_seq); ctrl->out_seq++; #ifdef DONT_HAVE_OUTSEQ_HACK ((u_int32_t*)(&(g[1])))[0]=htonl(0); #endif memcpy(((char*)g)+sizeof(struct pptp_gre_header)+4,data,len); do_send_gre_packet(ctrl,g); } else { size=len+sizeof(struct pptp_gre_header)+4; g=(struct pptp_gre_header *)buf; g->flags=PPTP_GRE_FLAG_K|PPTP_GRE_FLAG_S; g->ver=PPTP_GRE_VER; g->payload_len=htons(len); g->call_id=ppp->call_id; ((u_int32_t*)(&(g[1])))[0]=htonl(ctrl->out_seq); ctrl->out_seq++; #ifdef DONT_HAVE_OUTSEQ_HACK ((u_int32_t*)(&(g[1])))[0]=htonl(0); #endif for(i=0;iout_window[i]!=NULL && SEQ(ctrl->out_window[i])>=ctrl->out_ack+ctrl->out_window_size+MAX_GRE_WINDOW-2 /*?*/ ) { free(ctrl->out_window[i]); ctrl->out_window[i]=NULL; } if(ctrl->out_window[i]==NULL) { if( (ctrl->out_window[i]=malloc(size)) != NULL ) { memcpy(ctrl->out_window[i],g,sizeof(struct pptp_gre_header)+4); memcpy(((char *)(ctrl->out_window[i]))+sizeof(struct pptp_gre_header)+4,data,len); } break; } } } return(0); }