| --- a/pppd/demand.c |
| +++ b/pppd/demand.c |
| @@ -40,6 +40,8 @@ |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <netdb.h> |
| +#include <unistd.h> |
| +#include <syslog.h> |
| #include <sys/param.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| @@ -47,6 +49,8 @@ |
| #include <sys/resource.h> |
| #include <sys/stat.h> |
| #include <sys/socket.h> |
| +#include <netinet/in.h> |
| +#include <arpa/inet.h> |
| #ifdef PPP_WITH_FILTER |
| #include <pcap-bpf.h> |
| #endif |
| @@ -223,6 +227,14 @@ loop_chars(unsigned char *p, int n) |
| int c, rv; |
| |
| rv = 0; |
| + |
| +/* check for synchronous connection... */ |
| + |
| + if ( (p[0] == 0xFF) && (p[1] == 0x03) ) { |
| + rv = loop_frame(p,n); |
| + return rv; |
| + } |
| + |
| for (; n > 0; --n) { |
| c = *p++; |
| if (c == PPP_FLAG) { |
| @@ -299,16 +311,100 @@ loop_frame(unsigned char *frame, int len |
| * loopback, now that the real serial link is up. |
| */ |
| void |
| -demand_rexmit(int proto) |
| +demand_rexmit(int proto, u_int32_t newip) |
| { |
| struct packet *pkt, *prev, *nextpkt; |
| + unsigned short checksum; |
| + unsigned short pkt_checksum = 0; |
| + unsigned iphdr; |
| + struct timeval tv; |
| + char cv = 0; |
| + char ipstr[16]; |
| |
| prev = NULL; |
| pkt = pend_q; |
| pend_q = NULL; |
| + tv.tv_sec = 1; |
| + tv.tv_usec = 0; |
| + select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */ |
| for (; pkt != NULL; pkt = nextpkt) { |
| nextpkt = pkt->next; |
| if (PPP_PROTOCOL(pkt->data) == proto) { |
| + if ( (proto == PPP_IP) && newip ) { |
| + /* Get old checksum */ |
| + |
| + iphdr = (pkt->data[4] & 15) << 2; |
| + checksum = *((unsigned short *) (pkt->data+14)); |
| + if (checksum == 0xFFFF) { |
| + checksum = 0; |
| + } |
| + |
| + |
| + if (pkt->data[13] == 17) { |
| + pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr)); |
| + if (pkt_checksum) { |
| + cv = 1; |
| + if (pkt_checksum == 0xFFFF) { |
| + pkt_checksum = 0; |
| + } |
| + } |
| + else { |
| + cv = 0; |
| + } |
| + } |
| + |
| + if (pkt->data[13] == 6) { |
| + pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr)); |
| + cv = 1; |
| + if (pkt_checksum == 0xFFFF) { |
| + pkt_checksum = 0; |
| + } |
| + } |
| + |
| + /* Delete old Source-IP-Address */ |
| + checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; |
| + checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; |
| + |
| + pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; |
| + pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; |
| + |
| + /* Change Source-IP-Address */ |
| + * ((u_int32_t *) (pkt->data + 16)) = newip; |
| + |
| + /* Add new Source-IP-Address */ |
| + checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; |
| + checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; |
| + |
| + pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; |
| + pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; |
| + |
| + /* Write new checksum */ |
| + if (!checksum) { |
| + checksum = 0xFFFF; |
| + } |
| + *((unsigned short *) (pkt->data+14)) = checksum; |
| + if (pkt->data[13] == 6) { |
| + *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum; |
| + } |
| + if (cv && (pkt->data[13] == 17) ) { |
| + *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum; |
| + } |
| + |
| + /* Log Packet */ |
| + strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16)))); |
| + if (pkt->data[13] == 1) { |
| + syslog(LOG_INFO,"Open ICMP %s -> %s\n", |
| + ipstr, |
| + inet_ntoa(*( (struct in_addr *) (pkt->data+20)))); |
| + } else { |
| + syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n", |
| + pkt->data[13] == 6 ? "TCP" : "UDP", |
| + ipstr, |
| + ntohs(*( (short *) (pkt->data+iphdr+4))), |
| + inet_ntoa(*( (struct in_addr *) (pkt->data+20))), |
| + ntohs(*( (short *) (pkt->data+iphdr+6)))); |
| + } |
| + } |
| output(0, pkt->data, pkt->length); |
| free(pkt); |
| } else { |
| --- a/pppd/ipcp.c |
| +++ b/pppd/ipcp.c |
| @@ -1915,7 +1915,7 @@ ipcp_up(fsm *f) |
| proxy_arp_set[f->unit] = 1; |
| |
| } |
| - demand_rexmit(PPP_IP); |
| + demand_rexmit(PPP_IP,go->ouraddr); |
| sifnpmode(f->unit, PPP_IP, NPMODE_PASS); |
| |
| } else { |
| --- a/pppd/ipv6cp.c |
| +++ b/pppd/ipv6cp.c |
| @@ -1338,7 +1338,7 @@ ipv6cp_up(fsm *f) |
| if (sif6defaultroute(f->unit, go->ourid, ho->hisid)) |
| default_route_set[f->unit] = 1; |
| } |
| - demand_rexmit(PPP_IPV6); |
| + demand_rexmit(PPP_IPV6,0); |
| sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); |
| |
| } else { |
| --- a/pppd/pppd-private.h |
| +++ b/pppd/pppd-private.h |
| @@ -368,7 +368,7 @@ void demand_conf(void); /* config interf |
| void demand_block(void); /* set all NPs to queue up packets */ |
| void demand_unblock(void); /* set all NPs to pass packets */ |
| void demand_discard(void); /* set all NPs to discard packets */ |
| -void demand_rexmit(int); /* retransmit saved frames for an NP */ |
| +void demand_rexmit(int, u_int32_t); /* retransmit saved frames for an NP */ |
| int loop_chars(unsigned char *, int); /* process chars from loopback */ |
| int loop_frame(unsigned char *, int); /* should we bring link up? */ |
| |