Beispiel #1
0
/*** decaps_gre ***************************************************************/
int decaps_gre (int fd, callback_t callback, int cl)
{
    unsigned char buffer[PACKET_MAX + 64 /*ip header*/];
    struct pptp_gre_header *header;
    int status, ip_len = 0;
    static int first = 1;
    unsigned int headersize;
    unsigned int payload_len;
    u_int32_t seq;

    if ((status = read (fd, buffer, sizeof(buffer))) <= 0) {
        warn("short read (%d): %s", status, strerror(errno));
        stats.rx_errors++;
        return -1;
    }
    /* strip off IP header, if present */
    if ((buffer[0] & 0xF0) == 0x40) 
        ip_len = (buffer[0] & 0xF) * 4;
    header = (struct pptp_gre_header *)(buffer + ip_len);
    /* verify packet (else discard) */
    if (    /* version should be 1 */
            ((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) ||
            /* PPTP-GRE protocol for PPTP */
            (ntoh16(header->protocol) != PPTP_GRE_PROTO)||
            /* flag C should be clear   */
            PPTP_GRE_IS_C(ntoh8(header->flags)) ||
            /* flag R should be clear   */
            PPTP_GRE_IS_R(ntoh8(header->flags)) ||
            /* flag K should be set     */
            (!PPTP_GRE_IS_K(ntoh8(header->flags))) ||
            /* routing and recursion ctrl = 0  */
            ((ntoh8(header->flags)&0xF) != 0)) {
        /* if invalid, discard this packet */
        warn("Discarding GRE: %X %X %X %X %X %X", 
                ntoh8(header->ver)&0x7F, ntoh16(header->protocol), 
                PPTP_GRE_IS_C(ntoh8(header->flags)),
                PPTP_GRE_IS_R(ntoh8(header->flags)), 
                PPTP_GRE_IS_K(ntoh8(header->flags)),
                ntoh8(header->flags) & 0xF);
        stats.rx_invalid++;
        return 0;
    }
    /* silently discard packets not for this call */
    if (ntoh16(header->call_id) != pptp_gre_call_id) return 0;
    /* test if acknowledgement present */
    if (PPTP_GRE_IS_A(ntoh8(header->ver))) { 
        u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))?
            header->ack:header->seq; /* ack in different place if S = 0 */
        ack = ntoh32( ack);
        if (ack > ack_recv) ack_recv = ack;
        /* also handle sequence number wrap-around  */
        if (WRAPPED(ack,ack_recv)) ack_recv = ack;
        if (ack_recv == stats.pt.seq) {
            int rtt = time_now_usecs() - stats.pt.time;
            stats.rtt = (stats.rtt + rtt) / 2;
        }
    }
    /* test if payload present */
    if (!PPTP_GRE_IS_S(ntoh8(header->flags)))
        return 0; /* ack, but no payload */
    headersize  = sizeof(*header);
    payload_len = ntoh16(header->payload_len);
    seq         = ntoh32(header->seq);
    /* no ack present? */
    if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize -= sizeof(header->ack);
    /* check for incomplete packet (length smaller than expected) */
    if (status - headersize < payload_len) {
        warn("discarding truncated packet (expected %d, got %d bytes)",
                payload_len, status - headersize);
        stats.rx_truncated++;
        return 0; 
    }
    /* check for expected sequence number */
    if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */
	if ( log_level >= 2 )
            log("accepting packet %d", seq);
        stats.rx_accepted++;
        first = 0;
        seq_recv = seq;
        return callback(cl, buffer + ip_len + headersize, payload_len);
    /* out of order, check if the number is too low and discard the packet. 
     * (handle sequence number wrap-around, and try to do it right) */
    } else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) {
	if ( log_level >= 1 )
            log("discarding duplicate or old packet %d (expecting %d)",
                seq, seq_recv + 1);
        stats.rx_underwin++;
    /* sequence number too high, is it reasonably close? */
    } else if ( seq < seq_recv + MISSING_WINDOW ||
                WRAPPED(seq, seq_recv + MISSING_WINDOW) ) {
	stats.rx_buffered++;
        if ( log_level >= 1 )
            log("%s packet %d (expecting %d, lost or reordered)",
                disable_buffer ? "accepting" : "buffering",
                seq, seq_recv+1);
        if ( disable_buffer ) {
            seq_recv = seq;
            stats.rx_lost += seq - seq_recv - 1;
            return callback(cl, buffer + ip_len + headersize, payload_len);
        } else {
            pqueue_add(seq, buffer + ip_len + headersize, payload_len);
	}
    /* no, packet must be discarded */
    } else {
	if ( log_level >= 1 )
            warn("discarding bogus packet %d (expecting %d)", 
		 seq, seq_recv + 1);
        stats.rx_overwin++;
    }
    return 0;
}
Beispiel #2
0
/*** encaps_gre ***************************************************************/
int encaps_gre (int fd, void *pack, unsigned int len)
{
    union {
        struct pptp_gre_header header;
        unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
    } u;
    static u_int32_t seq = 1; /* first sequence number sent must be 1 */
    unsigned int header_len;
    int rc;
    /* package this up in a GRE shell. */
    u.header.flags       = hton8 (PPTP_GRE_FLAG_K);
    u.header.ver         = hton8 (PPTP_GRE_VER);
    u.header.protocol    = hton16(PPTP_GRE_PROTO);
    u.header.payload_len = hton16(len);
    u.header.call_id     = hton16(pptp_gre_peer_call_id);
    /* special case ACK with no payload */
    if (pack == NULL) {
        if (ack_sent != seq_recv) {
            u.header.ver |= hton8(PPTP_GRE_FLAG_A);
            u.header.payload_len = hton16(0);
            /* ack is in odd place because S == 0 */
            u.header.seq = hton32(seq_recv);
            ack_sent = seq_recv;
            rc = (*my->write)(fd, &u.header,
                                 sizeof(u.header) - sizeof(u.header.seq));
            if (rc < 0) {
                if (errno == ENOBUFS)
                    rc = 0;         /* Simply ignore it */
                stats.tx_failed++;
            } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) {
                stats.tx_short++;
            } else {
                stats.tx_acks++;
            }
            return rc;
        } else return 0; /* we don't need to send ACK */
    } /* explicit brace to avoid ambiguous `else' warning */
    /* send packet with payload */
    u.header.flags |= hton8(PPTP_GRE_FLAG_S);
    u.header.seq    = hton32(seq);
    if (ack_sent != seq_recv) { /* send ack with this message */
        u.header.ver |= hton8(PPTP_GRE_FLAG_A);
        u.header.ack  = hton32(seq_recv);
        ack_sent = seq_recv;
        header_len = sizeof(u.header);
    } else { /* don't send ack */
        header_len = sizeof(u.header) - sizeof(u.header.ack);
    }
    if (header_len + len >= sizeof(u.buffer)) {
        stats.tx_oversize++;
        return 0; /* drop this, it's too big */
    }
    /* copy payload into buffer */
    memcpy(u.buffer + header_len, pack, len);
    /* record and increment sequence numbers */
    seq_sent = seq; seq++;
    /* write this baby out to the net */
    /* print_packet(2, u.buffer, header_len + len); */
    rc = (*my->write)(fd, u.buffer, header_len + len);
    if (rc < 0) {
        if (errno == ENOBUFS)
            rc = 0;         /* Simply ignore it */
        stats.tx_failed++;
    } else if (rc < header_len + len) {
        stats.tx_short++;
    } else {
        stats.tx_sent++;
        stats.pt.seq  = seq_sent;
        stats.pt.time = time_now_usecs();
    }
    return rc;
}
Beispiel #3
0
/*** encaps_gre ***************************************************************/
int encaps_gre (int fd, void *pack, unsigned int len)
{
    union {
        struct pptp_gre_header header;
        unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
    } u;
    //static u_int32_t seq = 1; /* first sequence number sent must be 1 */
    unsigned int header_len;
    int rc;
    /*  added start, Winster Chan, 06/26/2006 */
    static u_int32_t kerseq; /* Sequence number got from kernel by ioctl() */
    /*  added end, Winster Chan, 06/26/2006 */

    /* package this up in a GRE shell. */
    u.header.flags       = hton8 (PPTP_GRE_FLAG_K);
    u.header.ver         = hton8 (PPTP_GRE_VER);
    u.header.protocol    = hton16(PPTP_GRE_PROTO);
    u.header.payload_len = hton16(len);
    u.header.call_id     = hton16(pptp_gre_peer_call_id);
    /* special case ACK with no payload */
    if (pack == NULL) {
        if (ack_sent != seq_recv) {
            u.header.ver |= hton8(PPTP_GRE_FLAG_A);
            u.header.payload_len = hton16(0);
            /* ack is in odd place because S == 0 */
            u.header.seq = hton32(seq_recv);
            ack_sent = seq_recv;
            rc = write(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq));
            if (rc < 0) {
                stats.tx_failed++;
            } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) {
                stats.tx_short++;
            } else {
                stats.tx_acks++;
            }
            return rc;
        } else return 0; /* we don't need to send ACK */
    } /* explicit brace to avoid ambiguous `else' warning */
    /* send packet with payload */
    u.header.flags |= hton8(PPTP_GRE_FLAG_S);
    /*  modified start, Winster Chan, 06/26/2006 */
    //u.header.seq    = hton32(seq);
    if (pox_fd >= 0) {
    	if (ioctl(pox_fd, PPTPIOCGGRESEQ, &kerseq) == -1) {
            warn("Couldn't get GRE sequence number");
        }
	}
	else
        warn("Socket not opened");
    u.header.seq    = hton32(kerseq);
    /*  modified end, Winster Chan, 06/26/2006 */
    if (ack_sent != seq_recv) { /* send ack with this message */
        u.header.ver |= hton8(PPTP_GRE_FLAG_A);
        u.header.ack  = hton32(seq_recv);
        ack_sent = seq_recv;
        header_len = sizeof(u.header);
    } else { /* don't send ack */
        header_len = sizeof(u.header) - sizeof(u.header.ack);
    }
    if (header_len + len >= sizeof(u.buffer)) {
        stats.tx_oversize++;
        return 0; /* drop this, it's too big */
    }
    /* copy payload into buffer */
    memcpy(u.buffer + header_len, pack, len);
    /* record and increment sequence numbers */
    /*  modified start, Winster Chan, 06/26/2006 */
    //seq_sent = seq; seq++;
    /*
     * Note: the kerseq(kernel sequence number) is maintained by
     *       pptp kernel driver
     */
    seq_sent = kerseq;
    /*  modified end, Winster Chan, 06/26/2006 */
    /* write this baby out to the net */
    /* print_packet(2, u.buffer, header_len + len); */
    rc = write(fd, u.buffer, header_len + len);
    if (rc < 0) {
        stats.tx_failed++;
    } else if (rc < header_len + len) {
        stats.tx_short++;
    } else {
        stats.tx_sent++;
        stats.pt.seq  = seq_sent;
        stats.pt.time = time_now_usecs();
    }
    return rc;
}