@@ -2,6 +2,7 @@ package vpn
22
33import (
44 "encoding/binary"
5+ "fmt"
56 "io"
67 "net"
78
@@ -61,12 +62,17 @@ func (data *Packet) clear() {
6162
6263func (data * Packet ) CopyTo (copyPacket * Packet ) {
6364 * copyPacket = * data
64- // set Packet reference to a new buffer
65+ // Buffer is an array copied by value above, but Packet/Src/Dst are slice
66+ // headers still aliasing data.Buffer. Re-derive them as sub-slices of the
67+ // copy's own buffer.
6568 copyPacket .Packet = copyPacket .Buffer [tunPacketOffset : len (data .Packet )+ tunPacketOffset ]
69+ if data .Src != nil {
70+ copyPacket .setAddrs ()
71+ }
6672}
6773
6874func (data * Packet ) ReadFrom (stream io.Reader ) (int64 , error ) {
69- var totalRead = tunPacketOffset
75+ totalRead : = tunPacketOffset
7076 for {
7177 n , err := stream .Read (data .Buffer [totalRead :])
7278 totalRead += n
@@ -76,6 +82,13 @@ func (data *Packet) ReadFrom(stream io.Reader) (int64, error) {
7682 } else if err != nil {
7783 return int64 (totalRead - tunPacketOffset ), err
7884 }
85+ // The buffer is sized with slack above the MTU (maxContentSize), so a
86+ // valid single-packet body never fills it. A full buffer means an
87+ // oversized frame; reject it instead of reading into the empty tail
88+ // (which would spin on (0, nil) reads).
89+ if totalRead == len (data .Buffer ) {
90+ return int64 (totalRead - tunPacketOffset ), fmt .Errorf ("packet body exceeds max size %d bytes" , MaxPacketBodySize )
91+ }
7992 }
8093}
8194
@@ -90,19 +103,25 @@ func (data *Packet) Parse() bool {
90103 if len (packet ) < ipv4 .HeaderLen {
91104 return false
92105 }
106+ // Validate the header length against the actual packet so downstream
107+ // slicing (RecalculateChecksum) can't run past the packet and panic.
108+ // Transport-length is not enforced here (it would drop legit non-first IP
109+ // fragments); RecalculateChecksum guards its own transport slicing.
110+ ipHeaderLen := int (packet [0 ]& 0x0f ) << 2
111+ if ipHeaderLen < ipv4 .HeaderLen || ipHeaderLen > len (packet ) {
112+ return false
113+ }
114+ data .IPProtocol = packet [9 ]
93115
94- data .Src = packet [device .IPv4offsetSrc : device .IPv4offsetSrc + net .IPv4len ]
95- data .Dst = packet [device .IPv4offsetDst : device .IPv4offsetDst + net .IPv4len ]
96116 data .IsIPv6 = false
97- data .IPProtocol = data . Packet [ 9 ]
117+ data .setAddrs ()
98118 case ipv6 .Version :
99119 if len (packet ) < ipv6 .HeaderLen {
100120 return false
101121 }
102122
103- data .Src = packet [device .IPv6offsetSrc : device .IPv6offsetSrc + net .IPv6len ]
104- data .Dst = packet [device .IPv6offsetDst : device .IPv6offsetDst + net .IPv6len ]
105123 data .IsIPv6 = true
124+ data .setAddrs ()
106125 // TODO: set data.IPProtocol
107126 default :
108127 return false
@@ -114,24 +133,45 @@ func (data *Packet) Parse() bool {
114133func (data * Packet ) RecalculateChecksum () {
115134 if data .IsIPv6 {
116135 // TODO
117- } else {
118- ipHeaderLen := int (data .Packet [0 ]& 0x0f ) << 2
119- copy (data .Packet [ipv4offsetChecksum :], []byte {0 , 0 })
120- ipChecksum := checksumIPv4Header (data .Packet [:ipHeaderLen ])
121- binary .BigEndian .PutUint16 (data .Packet [ipv4offsetChecksum :], ipChecksum )
122-
123- switch protocol := data .Packet [9 ]; protocol {
124- case IPProtocolTCP :
125- tcpOffsetChecksum := ipHeaderLen + 16
126- copy (data .Packet [tcpOffsetChecksum :], []byte {0 , 0 })
127- checksum := checksumIPv4TCPUDP (data .Packet [ipHeaderLen :], uint32 (protocol ), data .Src , data .Dst )
128- binary .BigEndian .PutUint16 (data .Packet [tcpOffsetChecksum :], checksum )
129- case IPProtocolUDP :
130- udpOffsetChecksum := ipHeaderLen + 6
131- copy (data .Packet [udpOffsetChecksum :], []byte {0 , 0 })
132- checksum := checksumIPv4TCPUDP (data .Packet [ipHeaderLen :], uint32 (protocol ), data .Src , data .Dst )
133- binary .BigEndian .PutUint16 (data .Packet [udpOffsetChecksum :], checksum )
136+ return
137+ }
138+ // Guard against malformed lengths so a bad packet can't slice past bounds and
139+ // panic, even if RecalculateChecksum is called without a prior valid Parse.
140+ ipHeaderLen := int (data .Packet [0 ]& 0x0f ) << 2
141+ if ipHeaderLen < ipv4 .HeaderLen || ipHeaderLen > len (data .Packet ) {
142+ return
143+ }
144+ copy (data .Packet [ipv4offsetChecksum :], []byte {0 , 0 })
145+ ipChecksum := checksumIPv4Header (data .Packet [:ipHeaderLen ])
146+ binary .BigEndian .PutUint16 (data .Packet [ipv4offsetChecksum :], ipChecksum )
147+
148+ switch protocol := data .Packet [9 ]; protocol {
149+ case IPProtocolTCP :
150+ if len (data .Packet ) < ipHeaderLen + 18 {
151+ return
134152 }
153+ tcpOffsetChecksum := ipHeaderLen + 16
154+ copy (data .Packet [tcpOffsetChecksum :], []byte {0 , 0 })
155+ checksum := checksumIPv4TCPUDP (data .Packet [ipHeaderLen :], uint32 (protocol ), data .Src , data .Dst )
156+ binary .BigEndian .PutUint16 (data .Packet [tcpOffsetChecksum :], checksum )
157+ case IPProtocolUDP :
158+ if len (data .Packet ) < ipHeaderLen + 8 {
159+ return
160+ }
161+ udpOffsetChecksum := ipHeaderLen + 6
162+ copy (data .Packet [udpOffsetChecksum :], []byte {0 , 0 })
163+ checksum := checksumIPv4TCPUDP (data .Packet [ipHeaderLen :], uint32 (protocol ), data .Src , data .Dst )
164+ binary .BigEndian .PutUint16 (data .Packet [udpOffsetChecksum :], checksum )
165+ }
166+ }
167+
168+ func (data * Packet ) setAddrs () {
169+ if data .IsIPv6 {
170+ data .Src = data .Packet [device .IPv6offsetSrc : device .IPv6offsetSrc + net .IPv6len ]
171+ data .Dst = data .Packet [device .IPv6offsetDst : device .IPv6offsetDst + net .IPv6len ]
172+ } else {
173+ data .Src = data .Packet [device .IPv4offsetSrc : device .IPv4offsetSrc + net .IPv4len ]
174+ data .Dst = data .Packet [device .IPv4offsetDst : device .IPv4offsetDst + net .IPv4len ]
135175 }
136176}
137177
0 commit comments