helpers.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package dhcp
  15. import (
  16. "encoding/binary"
  17. "fmt"
  18. "net"
  19. "strings"
  20. "time"
  21. "yunion.io/x/log"
  22. "yunion.io/x/onecloud/pkg/util/netutils2"
  23. )
  24. const (
  25. PXECLIENT = "PXEClient"
  26. OptClasslessRouteLin OptionCode = OptionClasslessRouteFormat //Classless Static Route Option
  27. OptClasslessRouteWin OptionCode = 249
  28. )
  29. // http://www.networksorcery.com/enp/rfc/rfc2132.txt
  30. type ResponseConfig struct {
  31. InterfaceMac net.HardwareAddr
  32. VlanId uint16
  33. OsName string
  34. ServerIP net.IP // OptServerIdentifier 54
  35. ClientIP net.IP
  36. Gateway net.IP // OptRouters 3
  37. Domain string // OptDomainName 15
  38. LeaseTime time.Duration // OptLeaseTime 51
  39. RenewalTime time.Duration // OptRenewalTime 58
  40. BroadcastAddr net.IP // OptBroadcastAddr 28
  41. Hostname string // OptHostname 12
  42. SubnetMask net.IP // OptSubnetMask 1
  43. DNSServers []net.IP // OptDNSServers
  44. Routes []netutils2.SRouteInfo // TODO: 249 for windows, 121 for linux
  45. NTPServers []net.IP // OptNTPServers 42
  46. MTU uint16 // OptMTU 26
  47. ClientIP6 net.IP
  48. Gateway6 net.IP
  49. PrefixLen6 uint8
  50. DNSServers6 []net.IP
  51. NTPServers6 []net.IP
  52. Routes6 []netutils2.SRouteInfo
  53. IsDefaultGW bool
  54. // Relay Info https://datatracker.ietf.org/doc/html/rfc3046
  55. RelayInfo []byte
  56. // TFTP config
  57. BootServer string
  58. BootFile string
  59. BootBlock uint16
  60. }
  61. func (conf ResponseConfig) GetHostname() string {
  62. return conf.Hostname
  63. }
  64. func GetOptUint16(val uint16) []byte {
  65. opts := []byte{0, 0}
  66. binary.BigEndian.PutUint16(opts, val)
  67. return opts
  68. }
  69. func GetOptUint32(val uint32) []byte {
  70. opts := []byte{0, 0, 0, 0}
  71. binary.BigEndian.PutUint32(opts, val)
  72. return opts
  73. }
  74. func GetOptIP(ip net.IP) []byte {
  75. return []byte(ip.To4())
  76. }
  77. func GetOptIPs(ips []net.IP) []byte {
  78. buf := make([]byte, 0)
  79. for _, ip := range ips {
  80. buf = append(buf, []byte(ip.To4())...)
  81. }
  82. return buf
  83. }
  84. func GetOptTime(d time.Duration) []byte {
  85. timeBytes := make([]byte, 4)
  86. binary.BigEndian.PutUint32(timeBytes, uint32(d/time.Second))
  87. return timeBytes
  88. }
  89. func getClasslessRoutePack(route netutils2.SRouteInfo) []byte {
  90. // var snet, gw = route[0], route[1]
  91. // tmp := strings.Split(snet, "/")
  92. netaddr := route.Prefix
  93. if netaddr != nil {
  94. netaddr = netaddr.To4()
  95. }
  96. masklen := route.PrefixLen
  97. netlen := masklen / 8
  98. if masklen%8 > 0 {
  99. netlen += 1
  100. }
  101. if netlen < 4 {
  102. netaddr = netaddr[0:netlen]
  103. }
  104. gwaddr := route.Gateway
  105. if gwaddr != nil {
  106. gwaddr = gwaddr.To4()
  107. }
  108. res := []byte{byte(masklen)}
  109. res = append(res, []byte(netaddr)...)
  110. return append(res, []byte(gwaddr)...)
  111. }
  112. func MakeReplyPacket(pkt Packet, conf *ResponseConfig) (Packet, error) {
  113. msgType := Offer
  114. if pkt.Type() == Request {
  115. reqAddr, _ := pkt.ParseOptions().IP(OptionRequestedIPAddress)
  116. if reqAddr != nil && !conf.ClientIP.Equal(reqAddr) {
  117. msgType = NAK
  118. } else {
  119. msgType = ACK
  120. }
  121. }
  122. return makeDHCPReplyPacket(pkt, conf, msgType), nil
  123. }
  124. func getPacketVendorClassId(pkt Packet) string {
  125. bs := pkt.ParseOptions()[OptionVendorClassIdentifier]
  126. vendorClsId := string(bs)
  127. return vendorClsId
  128. }
  129. func makeDHCPReplyPacket(req Packet, conf *ResponseConfig, msgType MessageType) Packet {
  130. if conf.OsName == "" {
  131. if vendorClsId := getPacketVendorClassId(req); vendorClsId != "" && strings.HasPrefix(vendorClsId, "MSFT ") {
  132. conf.OsName = "win"
  133. }
  134. }
  135. opts := make([]Option, 0)
  136. if conf.SubnetMask != nil {
  137. opts = append(opts, Option{Code: OptionSubnetMask, Value: GetOptIP(conf.SubnetMask)})
  138. }
  139. if conf.Gateway != nil {
  140. opts = append(opts, Option{Code: OptionRouter, Value: GetOptIP(conf.Gateway)})
  141. }
  142. if conf.Domain != "" {
  143. opts = append(opts, Option{Code: OptionDomainName, Value: []byte(conf.Domain)})
  144. }
  145. if conf.BroadcastAddr != nil {
  146. opts = append(opts, Option{Code: OptionBroadcastAddress, Value: GetOptIP(conf.BroadcastAddr)})
  147. }
  148. if conf.Hostname != "" {
  149. opts = append(opts, Option{Code: OptionHostName, Value: []byte(conf.GetHostname())})
  150. }
  151. if len(conf.DNSServers) > 0 {
  152. opts = append(opts, Option{Code: OptionDomainNameServer, Value: GetOptIPs(conf.DNSServers)})
  153. }
  154. if len(conf.NTPServers) > 0 {
  155. opts = append(opts, Option{Code: OptionNetworkTimeProtocolServers, Value: GetOptIPs(conf.NTPServers)})
  156. }
  157. if conf.MTU > 0 {
  158. opts = append(opts, Option{Code: OptionInterfaceMTU, Value: GetOptUint16(conf.MTU)})
  159. }
  160. if conf.RelayInfo != nil {
  161. opts = append(opts, Option{Code: OptionRelayAgentInformation, Value: conf.RelayInfo})
  162. }
  163. var clientIP net.IP
  164. if conf.ClientIP != nil {
  165. clientIP = conf.ClientIP
  166. } else {
  167. clientIP = net.ParseIP("0.0.0.0")
  168. opts = append(opts, Option{Code: OptionIPv6Only, Value: GetOptUint32(60)})
  169. }
  170. resp := ReplyPacket(req, msgType, conf.ServerIP, clientIP, conf.LeaseTime, opts)
  171. if conf.BootServer != "" {
  172. //resp.Options[OptOverload] = []byte{3}
  173. resp.SetSIAddr(net.ParseIP(conf.BootServer))
  174. resp.AddOption(OptionTFTPServerName, []byte(fmt.Sprintf("%s\x00", conf.BootServer)))
  175. }
  176. if conf.BootFile != "" {
  177. resp.AddOption(OptionBootFileName, []byte(fmt.Sprintf("%s\x00", conf.BootFile)))
  178. sz := make([]byte, 2)
  179. binary.BigEndian.PutUint16(sz, conf.BootBlock)
  180. resp.AddOption(OptionBootFileSize, sz)
  181. }
  182. //if bs, _ := req.ParseOptions().Bytes(OptionClientMachineIdentifier); bs != nil {
  183. //resp.AddOption(OptionClientMachineIdentifier, bs)
  184. //}
  185. if conf.RenewalTime > 0 {
  186. resp.AddOption(OptionRenewalTimeValue, GetOptTime(conf.RenewalTime))
  187. }
  188. if conf.Routes != nil {
  189. var optCode = OptClasslessRouteLin
  190. if strings.HasPrefix(strings.ToLower(conf.OsName), "win") {
  191. optCode = OptClasslessRouteWin
  192. }
  193. for _, route := range conf.Routes {
  194. routeBytes := getClasslessRoutePack(route)
  195. resp.AddOption(optCode, routeBytes)
  196. }
  197. }
  198. return resp
  199. }
  200. func IsPXERequest(pkt Packet) bool {
  201. //if pkt.Type != MsgDiscover {
  202. //log.Warningf("packet is %s, not %s", pkt.Type, MsgDiscover)
  203. //return false
  204. //}
  205. if pkt.GetOptionValue(OptionClientArchitecture) == nil {
  206. log.Debugf("%s not a PXE boot request (missing option 93)", pkt.CHAddr().String())
  207. return false
  208. }
  209. return true
  210. }