Переглянути джерело

fixed aliasing and alignment issues

Eugene Yakubovich 10 роки тому
батько
коміт
8f12eb4e94
3 змінених файлів з 31 додано та 34 видалено
  1. 1 1
      pkg/ipnet.go
  2. 4 4
      udp/cproxy.go
  3. 26 29
      udp/proxy.c

+ 1 - 1
pkg/ipnet.go

@@ -48,7 +48,7 @@ func (ip IP4) ToIP() net.IP {
 	return net.IPv4(ip.Octets())
 }
 
-func (ip IP4) ToNetworkOrder() uint32 {
+func (ip IP4) NetworkOrder() uint32 {
 	if NativelyLittle() {
 		a, b, c, d := byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip)
 		return uint32(a) | (uint32(b) << 8) | (uint32(c) << 16) | (uint32(d) << 24)

+ 4 - 4
udp/cproxy.go

@@ -28,7 +28,7 @@ func runCProxy(tun *os.File, conn *os.File, ctl *os.File, tunIP pkg.IP4) {
 		C.int(tun.Fd()),
 		C.int(conn.Fd()),
 		C.int(ctl.Fd()),
-		C.in_addr_t(tunIP.ToNetworkOrder()),
+		C.in_addr_t(tunIP.NetworkOrder()),
 		C.int(log_errors),
 	)
 
@@ -93,9 +93,9 @@ func fastProxy(sm *subnet.SubnetManager, tun *os.File, conn *net.UDPConn, tunIP
 
 				cmd := C.command{
 					cmd:           C.CMD_SET_ROUTE,
-					dest_net:      C.in_addr_t(evt.Lease.Network.IP.ToNetworkOrder()),
+					dest_net:      C.in_addr_t(evt.Lease.Network.IP.NetworkOrder()),
 					dest_net_len:  C.int(evt.Lease.Network.PrefixLen),
-					next_hop_ip:   C.in_addr_t(attrs.PublicIP.ToNetworkOrder()),
+					next_hop_ip:   C.in_addr_t(attrs.PublicIP.NetworkOrder()),
 					next_hop_port: C.short(port),
 				}
 
@@ -106,7 +106,7 @@ func fastProxy(sm *subnet.SubnetManager, tun *os.File, conn *net.UDPConn, tunIP
 
 				cmd := C.command{
 					cmd:          C.CMD_DEL_ROUTE,
-					dest_net:     C.in_addr_t(evt.Lease.Network.IP.ToNetworkOrder()),
+					dest_net:     C.in_addr_t(evt.Lease.Network.IP.NetworkOrder()),
 					dest_net_len: C.int(evt.Lease.Network.PrefixLen),
 				}
 

+ 26 - 29
udp/proxy.c

@@ -33,7 +33,10 @@ typedef struct icmp_pkt {
 	/* dest unreachable must include IP hdr 8 bytes of upper layer proto
 	 * of the original packet. */
 	char    data[sizeof(struct iphdr) + MAX_IPOPTLEN + 8];
-} icmp_pkt;
+} __attribute__ ((aligned (4))) icmp_pkt;
+
+/* we calc hdr checksums using 32bit uints that can alias other types */
+typedef uint32_t __attribute__((__may_alias__)) aliasing_uint32_t;
 
 struct route_entry *routes;
 size_t routes_alloc;
@@ -63,20 +66,15 @@ static void log_error(const char *fmt, ...) {
 }
 
 /* fast version -- only works with mults of 4 bytes */
-uint16_t cksum(char* buf, int len) {
+uint16_t cksum(aliasing_uint32_t *buf, int len) {
 	uint32_t sum = 0;
-	const uint32_t *b = (uint32_t*) buf;
-
 	uint16_t t1, t2;
 
-	assert(len % 4 == 0);
-
-	while( len > 0 ) {
-		uint32_t s = *b++;
+	for( ; len > 0; len-- ) {
+		uint32_t s = *buf++;
 		sum += s;
 		if( sum < s )
 			sum++;
-		len -= 4;
 	}
 
 	/* Fold down to 16 bits */
@@ -118,14 +116,14 @@ static void send_net_unreachable(int tun, char *offender) {
 	memset(&pkt, 0, sizeof(pkt));
 
 	/* Fill in the IP header */
-	pkt.iph.ihl = 5;
+	pkt.iph.ihl = sizeof(struct iphdr) / 4;
 	pkt.iph.version = IPVERSION;
 	pkt.iph.tot_len = htons(pktlen);
 	pkt.iph.ttl = 8;
 	pkt.iph.protocol = IPPROTO_ICMP;
 	pkt.iph.saddr = tun_addr;
 	pkt.iph.daddr = off_iph->saddr;
-	pkt.iph.check = cksum((char *)&pkt.iph, sizeof(struct iphdr));
+	pkt.iph.check = cksum((aliasing_uint32_t*) &pkt.iph, sizeof(struct iphdr) / sizeof(aliasing_uint32_t));
 
 	/* Fill in the ICMP header */
 	pkt.icmph.type = ICMP_DEST_UNREACH;
@@ -135,7 +133,8 @@ static void send_net_unreachable(int tun, char *offender) {
 	memcpy(pkt.data, offender, off_iph_len + 8);
 
 	/* Compute the checksum over the ICMP header and data */
-	pkt.icmph.checksum = cksum((char *)&pkt.icmph, sizeof(struct icmphdr) + off_iph_len + 8);
+	pkt.icmph.checksum = cksum((aliasing_uint32_t*) &pkt.icmph,
+			(sizeof(struct icmphdr) + off_iph_len + 8) / sizeof(aliasing_uint32_t));
 
 	/* Kick it back */
 	nsent = write(tun, &pkt, pktlen);
@@ -274,7 +273,7 @@ static void tun_send_packet(int tun, char *pkt, size_t pktlen) {
 }
 
 static void tun_to_udp(int tun, int sock) {
-	char buf[MTU];
+	char buf[MTU] __attribute__ ((aligned (4)));
 
 	struct iphdr *iph;
 	struct sockaddr_in *next_hop;
@@ -301,13 +300,13 @@ static void tun_to_udp(int tun, int sock) {
 
 	/* TTL modified, need to recompute checksum */
 	iph->check = 0;
-	iph->check = cksum((char *)iph, iph->ihl * 4);
+	iph->check = cksum((aliasing_uint32_t*) iph, iph->ihl);
 
 	sock_send_packet(sock, buf, pktlen, next_hop);
 }
 
 static void udp_to_tun(int sock, int tun) {
-	char buf[MTU];
+	char buf[MTU] __attribute__ ((aligned (4)));
 	struct iphdr *iph;
 
 	ssize_t pktlen = recv(sock, buf, MTU, 0);
@@ -327,42 +326,40 @@ static void udp_to_tun(int sock, int tun) {
 
 	/* TTL modified, need to recompute checksum */
 	iph->check = 0;
-	iph->check = cksum((char *)iph, iph->ihl * 4);
+	iph->check = cksum((aliasing_uint32_t*) iph, iph->ihl);
 
 	tun_send_packet(tun, buf, pktlen);
 }
 
 static void process_cmd(int ctl) {
-	char buf[128];
+	struct command cmd;
 	struct ip_net ipn;
 	struct sockaddr_in sa = {
 		.sin_family = AF_INET
 	};
 
-	ssize_t nrecv = recv(ctl, buf, sizeof(buf), 0);
+	ssize_t nrecv = recv(ctl, (char *) &cmd, sizeof(cmd), 0);
 	if( nrecv < 0 ) {
 		log_error("CTL recv failed: %s\n", strerror(errno));
 		return;
 	}
 
-	struct command *cmd = (struct command *)buf;
-
-	if( cmd->cmd == CMD_SET_ROUTE ) {
-		ipn.mask = netmask(cmd->dest_net_len);
-		ipn.ip = cmd->dest_net & ipn.mask;
+	if( cmd.cmd == CMD_SET_ROUTE ) {
+		ipn.mask = netmask(cmd.dest_net_len);
+		ipn.ip = cmd.dest_net & ipn.mask;
 
-		sa.sin_addr.s_addr = cmd->next_hop_ip;
-		sa.sin_port = htons(cmd->next_hop_port);
+		sa.sin_addr.s_addr = cmd.next_hop_ip;
+		sa.sin_port = htons(cmd.next_hop_port);
 
 		set_route(ipn, &sa);
 
-	} else if( cmd->cmd == CMD_DEL_ROUTE ) {
-		ipn.mask = netmask(cmd->dest_net_len);
-		ipn.ip = cmd->dest_net & ipn.mask;
+	} else if( cmd.cmd == CMD_DEL_ROUTE ) {
+		ipn.mask = netmask(cmd.dest_net_len);
+		ipn.ip = cmd.dest_net & ipn.mask;
 
 		del_route(ipn);
 
-	} else if( cmd->cmd == CMD_STOP ) {
+	} else if( cmd.cmd == CMD_STOP ) {
 		exit_flag = 1;
 	}
 }