dhcpserver.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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 hostdhcp
  15. import (
  16. "net"
  17. "strings"
  18. "time"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/netutils"
  22. "yunion.io/x/onecloud/pkg/apis"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/types"
  24. "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
  25. guestman "yunion.io/x/onecloud/pkg/hostman/guestman/types"
  26. "yunion.io/x/onecloud/pkg/hostman/options"
  27. "yunion.io/x/onecloud/pkg/util/dhcp"
  28. "yunion.io/x/onecloud/pkg/util/netutils2"
  29. )
  30. const (
  31. DEFAULT_DHCP_SERVER_PORT = 67
  32. // DEFAULT_DHCP_CLIENT_PORT = 68
  33. DEFAULT_DHCP_RELAY_PORT = 68
  34. )
  35. type SGuestDHCPServer struct {
  36. server *dhcp.DHCPServer
  37. relay *SDHCPRelay
  38. conn *dhcp.Conn
  39. ifaceDev *netutils2.SNetInterface
  40. }
  41. type SDHCPRelayUpstream struct {
  42. IP string
  43. Port int
  44. }
  45. func NewGuestDHCPServer(iface string, port int, relay *SDHCPRelayUpstream) (*SGuestDHCPServer, error) {
  46. var (
  47. err error
  48. guestdhcp = new(SGuestDHCPServer)
  49. )
  50. dev := netutils2.NewNetInterface(iface)
  51. if dev.GetHardwareAddr() == nil {
  52. return nil, errors.Wrapf(errors.ErrInvalidStatus, "iface %s no mac", iface)
  53. }
  54. guestdhcp.ifaceDev = dev
  55. guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, DEFAULT_DHCP_SERVER_PORT)
  56. if err != nil {
  57. return nil, errors.Wrap(err, "dhcp.NewDHCPServer2")
  58. }
  59. if relay != nil {
  60. guestdhcp.relay, err = NewDHCPRelay(guestdhcp.conn, relay)
  61. if err != nil {
  62. return nil, errors.Wrap(err, "NewDHCPRelay")
  63. }
  64. }
  65. return guestdhcp, nil
  66. }
  67. func (s *SGuestDHCPServer) Start(blocking bool) {
  68. log.Infof("SGuestDHCPServer %s starting (blocking: %v) ...", s.ifaceDev.String(), blocking)
  69. serve := func() {
  70. err := s.server.ListenAndServe(s)
  71. if err != nil {
  72. log.Errorf("DHCP serve error: %s", err)
  73. }
  74. }
  75. if blocking {
  76. serve()
  77. } else {
  78. go serve()
  79. }
  80. }
  81. func (s *SGuestDHCPServer) RelaySetup(addr string) error {
  82. if s.relay != nil {
  83. return s.relay.Setup(addr)
  84. }
  85. return nil
  86. }
  87. func gusetnetworkJsonDescToServerNic(nicdesc *types.SServerNic, guestNic *desc.SGuestNetwork) error {
  88. if guestNic.Routes != nil {
  89. if err := guestNic.Routes.Unmarshal(&nicdesc.Routes); err != nil {
  90. return err
  91. }
  92. }
  93. nicdesc.Index = int(guestNic.Index)
  94. nicdesc.Bridge = guestNic.Bridge
  95. if !apis.IsIllegalSearchDomain(guestNic.Domain) {
  96. nicdesc.Domain = guestNic.Domain
  97. }
  98. nicdesc.Ip = guestNic.Ip
  99. nicdesc.Vlan = guestNic.Vlan
  100. nicdesc.Driver = guestNic.Driver
  101. nicdesc.Masklen = int(guestNic.Masklen)
  102. nicdesc.Virtual = guestNic.Virtual
  103. if guestNic.Manual != nil {
  104. nicdesc.Manual = *guestNic.Manual
  105. }
  106. nicdesc.WireId = guestNic.WireId
  107. nicdesc.NetId = guestNic.NetId
  108. nicdesc.Mac = guestNic.Mac
  109. nicdesc.Mtu = guestNic.Mtu
  110. nicdesc.Dns = guestNic.Dns
  111. nicdesc.Ntp = guestNic.Ntp
  112. nicdesc.Net = guestNic.Net
  113. nicdesc.Interface = guestNic.Interface
  114. nicdesc.Gateway = guestNic.Gateway
  115. nicdesc.Ifname = guestNic.Ifname
  116. nicdesc.NicType = guestNic.NicType
  117. nicdesc.LinkUp = guestNic.LinkUp
  118. nicdesc.TeamWith = guestNic.TeamWith
  119. nicdesc.IsDefault = guestNic.IsDefault
  120. nicdesc.Ip6 = guestNic.Ip6
  121. nicdesc.Masklen6 = int(guestNic.Masklen6)
  122. nicdesc.Gateway6 = guestNic.Gateway6
  123. return nil
  124. }
  125. func GetMainNic(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
  126. for _, n := range nics {
  127. if n.IsDefault {
  128. return n
  129. }
  130. }
  131. for _, n := range nics {
  132. if n.Ip != "" && n.Gateway != "" {
  133. return n
  134. }
  135. }
  136. return nil
  137. }
  138. func GetMainNic6(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
  139. for _, n := range nics {
  140. if n.IsDefault {
  141. return n
  142. }
  143. }
  144. for _, n := range nics {
  145. if n.Ip6 != "" && n.Gateway6 != "" {
  146. return n
  147. }
  148. }
  149. return nil
  150. }
  151. func getGuestConfig(
  152. guestDesc *desc.SGuestDesc, guestNic *desc.SGuestNetwork,
  153. serverMac net.HardwareAddr,
  154. ) *dhcp.ResponseConfig {
  155. var nicdesc = new(types.SServerNic)
  156. if err := gusetnetworkJsonDescToServerNic(nicdesc, guestNic); err != nil {
  157. log.Errorf("failed convert server nic desc")
  158. return nil
  159. }
  160. var conf = new(dhcp.ResponseConfig)
  161. conf.InterfaceMac = serverMac
  162. conf.VlanId = uint16(nicdesc.Vlan)
  163. if len(nicdesc.Ip) > 0 {
  164. nicIp := nicdesc.Ip
  165. v4Ip, _ := netutils.NewIPV4Addr(nicIp)
  166. conf.ClientIP = net.ParseIP(nicdesc.Ip)
  167. masklen := nicdesc.Masklen
  168. conf.ServerIP = net.ParseIP(v4Ip.NetAddr(int8(masklen)).String())
  169. conf.SubnetMask = net.ParseIP(netutils2.Netlen2Mask(int(masklen)))
  170. conf.BroadcastAddr = v4Ip.BroadcastAddr(int8(masklen)).ToBytes()
  171. if nicdesc.Gateway != "" {
  172. conf.Gateway = net.ParseIP(nicdesc.Gateway)
  173. }
  174. }
  175. if len(guestDesc.Hostname) > 0 {
  176. conf.Hostname = guestDesc.Hostname
  177. } else {
  178. conf.Hostname = guestDesc.Name
  179. }
  180. conf.Hostname = strings.ToLower(conf.Hostname)
  181. conf.Domain = nicdesc.Domain
  182. if len(nicdesc.Ip6) > 0 {
  183. // ipv6
  184. conf.ClientIP6 = net.ParseIP(nicdesc.Ip6)
  185. conf.PrefixLen6 = uint8(nicdesc.Masklen6)
  186. if nicdesc.Gateway6 != "" {
  187. conf.Gateway6 = net.ParseIP(nicdesc.Gateway6)
  188. }
  189. }
  190. // get main ip
  191. guestNics := guestDesc.Nics
  192. mainNic := GetMainNic(guestNics)
  193. var mainIp string
  194. if mainNic != nil {
  195. mainIp = mainNic.Ip
  196. }
  197. mainNic6 := GetMainNic6(guestNics)
  198. var mainIp6 string
  199. if mainNic6 != nil {
  200. mainIp6 = mainNic6.Ip6
  201. }
  202. route4 := make([]netutils2.SRouteInfo, 0)
  203. route6 := make([]netutils2.SRouteInfo, 0)
  204. if nicdesc.IsDefault {
  205. conf.IsDefaultGW = true
  206. osName := guestDesc.OsName
  207. if len(osName) == 0 {
  208. osName = "Linux"
  209. }
  210. if conf.Gateway != nil {
  211. if !strings.HasPrefix(strings.ToLower(osName), "win") {
  212. route4 = append(route4, netutils2.SRouteInfo{
  213. SPrefixInfo: netutils2.SPrefixInfo{
  214. Prefix: net.ParseIP("0.0.0.0"),
  215. PrefixLen: 0,
  216. },
  217. Gateway: conf.Gateway,
  218. })
  219. }
  220. }
  221. //if conf.Gateway6 != nil {
  222. /*route6 = append(route6, netutils2.SRouteInfo{
  223. SPrefixInfo: netutils2.SPrefixInfo{
  224. Prefix: net.ParseIP("::"),
  225. PrefixLen: 0,
  226. },
  227. Gateway: conf.Gateway6,
  228. })*/
  229. //}
  230. }
  231. route4, route6 = netutils2.AddNicRoutes(route4, route6, nicdesc, mainIp, mainIp6, len(guestNics))
  232. conf.Routes = route4
  233. conf.Routes6 = route6
  234. if len(nicdesc.Dns) > 0 {
  235. conf.DNSServers, conf.DNSServers6 = netutils2.SplitV46Addr2IP(nicdesc.Dns)
  236. }
  237. if len(nicdesc.Ntp) > 0 {
  238. conf.NTPServers, conf.NTPServers6 = netutils2.SplitV46Addr2IP(nicdesc.Ntp)
  239. }
  240. if nicdesc.Mtu > 0 {
  241. conf.MTU = uint16(nicdesc.Mtu)
  242. }
  243. conf.OsName = guestDesc.OsName
  244. conf.LeaseTime = time.Duration(options.HostOptions.DhcpLeaseTime) * time.Second
  245. conf.RenewalTime = time.Duration(options.HostOptions.DhcpRenewalTime) * time.Second
  246. return conf
  247. }
  248. func (s *SGuestDHCPServer) getConfig(pkt dhcp.Packet) *dhcp.ResponseConfig {
  249. if guestman.GuestDescGetter == nil {
  250. return nil
  251. }
  252. var (
  253. mac = pkt.CHAddr().String()
  254. ip, port = "", ""
  255. isCandidate = false
  256. )
  257. guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), isCandidate)
  258. if guestNic == nil {
  259. guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), !isCandidate)
  260. }
  261. if guestNic != nil && !guestNic.Virtual {
  262. return getGuestConfig(guestDesc, guestNic, s.ifaceDev.GetHardwareAddr())
  263. }
  264. return nil
  265. }
  266. func (s *SGuestDHCPServer) IsDhcpPacket(pkt dhcp.Packet) bool {
  267. return pkt != nil && (pkt.Type() == dhcp.Request || pkt.Type() == dhcp.Discover)
  268. }
  269. func (s *SGuestDHCPServer) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
  270. pkg, err := s.serveDHCPInternal(pkt, addr)
  271. return pkg, nil, err
  272. }
  273. func (s *SGuestDHCPServer) serveDHCPInternal(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
  274. if !s.IsDhcpPacket(pkt) {
  275. return nil, nil
  276. }
  277. var conf = s.getConfig(pkt)
  278. if conf != nil {
  279. log.Infof("Make DHCP Reply %s TO %s %s", conf.ClientIP, pkt.CHAddr(), addr.String())
  280. // Guest request ip
  281. return dhcp.MakeReplyPacket(pkt, conf)
  282. } else if s.relay != nil && s.relay.server != nil {
  283. // Host agent as dhcp relay, relay to baremetal
  284. return s.relay.Relay(pkt, addr)
  285. }
  286. return nil, nil
  287. }