-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Christopher Koch <[email protected]>
- Loading branch information
Showing
5 changed files
with
187 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package dhcpv4 | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"strings" | ||
|
||
"github.com/u-root/u-root/pkg/uio" | ||
) | ||
|
||
// Route is a classless static route as per RFC 3442. | ||
type Route struct { | ||
// Dest is the destination network. | ||
Dest *net.IPNet | ||
|
||
// Router is the router to use for the given destination network. | ||
Router net.IP | ||
} | ||
|
||
// Marshal implements uio.Marshaler. | ||
// | ||
// Format described in RFC 3442: | ||
// | ||
// <size of mask in number of bits> | ||
// <destination address, omitting octets that must be zero per mask> | ||
// <route IP> | ||
func (r Route) Marshal(buf *uio.Lexer) { | ||
ones, _ := r.Dest.Mask.Size() | ||
buf.Write8(uint8(ones)) | ||
|
||
// Only write the non-zero octets. | ||
dstLen := (ones + 7) / 8 | ||
buf.WriteBytes(r.Dest.IP.To4()[:dstLen]) | ||
|
||
buf.WriteBytes(r.Router.To4()) | ||
} | ||
|
||
// Unmarshal implements uio.Unmarshaler. | ||
func (r *Route) Unmarshal(buf *uio.Lexer) error { | ||
maskSize := buf.Read8() | ||
r.Dest = &net.IPNet{ | ||
IP: make([]byte, net.IPv4len), | ||
Mask: net.CIDRMask(int(maskSize), 32), | ||
} | ||
|
||
dstLen := (maskSize + 7) / 8 | ||
buf.ReadBytes(r.Dest.IP[:dstLen]) | ||
|
||
r.Router = buf.CopyN(net.IPv4len) | ||
return buf.Error() | ||
} | ||
|
||
// String prints the destination network and router IP. | ||
func (r *Route) String() string { | ||
return fmt.Sprintf("route to %s via %s", r.Dest, r.Router) | ||
} | ||
|
||
// Routes is a collection of network routes. | ||
type Routes []*Route | ||
|
||
// FromBytes parses routes from a set of bytes as described by RFC 3442. | ||
func (r *Routes) FromBytes(p []byte) error { | ||
buf := uio.NewBigEndianBuffer(p) | ||
for buf.Has(1) { | ||
var route Route | ||
if err := route.Unmarshal(buf); err != nil { | ||
return err | ||
} | ||
*r = append(*r, &route) | ||
} | ||
return buf.FinError() | ||
} | ||
|
||
// ToBytes marshals a set of routes as described by RFC 3442. | ||
func (r Routes) ToBytes() []byte { | ||
buf := uio.NewBigEndianBuffer(nil) | ||
for _, route := range r { | ||
route.Marshal(buf) | ||
} | ||
return buf.Data() | ||
} | ||
|
||
// String prints all routes. | ||
func (r Routes) String() string { | ||
s := make([]string, 0, len(r)) | ||
for _, route := range r { | ||
s = append(s, route.String()) | ||
} | ||
return strings.Join(s, "; ") | ||
} | ||
|
||
// OptClasslessStaticRoute returns a new DHCPv4 Classless Static Route | ||
// option. | ||
// | ||
// The Classless Static Route option is described by RFC 3442. | ||
func OptClasslessStaticRoute(routes ...*Route) Option { | ||
return Option{ | ||
Code: OptionClasslessStaticRoute, | ||
Value: Routes(routes), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package dhcpv4 | ||
|
||
import ( | ||
"net" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func mustParseIPNet(s string) *net.IPNet { | ||
_, ipnet, err := net.ParseCIDR(s) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return ipnet | ||
} | ||
|
||
func TestParseRoutes(t *testing.T) { | ||
for _, tt := range []struct { | ||
p []byte | ||
want Routes | ||
err error | ||
}{ | ||
{ | ||
p: []byte{32, 10, 2, 3, 4, 0, 0, 0, 0}, | ||
want: Routes{ | ||
&Route{ | ||
Dest: mustParseIPNet("10.2.3.4/32"), | ||
Router: net.IP{0, 0, 0, 0}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
p: []byte{0, 0, 0, 0, 0}, | ||
want: Routes{ | ||
&Route{ | ||
Dest: mustParseIPNet("0.0.0.0/0"), | ||
Router: net.IP{0, 0, 0, 0}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
p: []byte{32, 10, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
want: Routes{ | ||
&Route{ | ||
Dest: mustParseIPNet("10.2.3.4/32"), | ||
Router: net.IP{0, 0, 0, 0}, | ||
}, | ||
&Route{ | ||
Dest: mustParseIPNet("0.0.0.0/0"), | ||
Router: net.IP{0, 0, 0, 0}, | ||
}, | ||
}, | ||
}, | ||
} { | ||
var r Routes | ||
if err := r.FromBytes(tt.p); err != tt.err { | ||
t.Errorf("FromBytes(%v) = %v, want %v", tt.p, err, tt.err) | ||
} | ||
|
||
if !reflect.DeepEqual(r, tt.want) { | ||
t.Errorf("FromBytes(%v) = %v, want %v", tt.p, r, tt.want) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters