| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package hostdhcp
- import (
- "fmt"
- "net"
- "sync"
- "time"
- "yunion.io/x/log"
- "yunion.io/x/onecloud/pkg/util/dhcp"
- )
- type recvFunc func(pkt *dhcp.Packet)
- type SRelayCache struct {
- mac net.HardwareAddr
- srcPort int
- // dstPort int
- timer time.Time
- }
- type SDHCPRelay struct {
- server *dhcp.DHCPServer
- OnRecv recvFunc
- guestDHCPConn *dhcp.Conn
- ipv4srcAddr net.IP
- destaddr net.IP
- destport int
- cache sync.Map
- }
- func NewDHCPRelay(guestDHCPConn *dhcp.Conn, config *SDHCPRelayUpstream) (*SDHCPRelay, error) {
- relay := new(SDHCPRelay)
- relay.guestDHCPConn = guestDHCPConn
- log.Infof("Set Relay To Address: %s, %d", config.IP, config.Port)
- relay.destaddr = net.ParseIP(config.IP)
- relay.destport = config.Port
- relay.cache = sync.Map{}
- return relay, nil
- }
- func (r *SDHCPRelay) Setup(addr string) error {
- r.ipv4srcAddr = net.ParseIP(addr)
- if len(r.ipv4srcAddr) == 0 {
- return fmt.Errorf("Wrong ip address %s", addr)
- }
- log.Infof("DHCP Relay Setup on %s %d", addr, DEFAULT_DHCP_RELAY_PORT)
- var err error
- r.server, err = dhcp.NewDHCPServer3(addr, DEFAULT_DHCP_RELAY_PORT)
- if err != nil {
- return err
- }
- go r.server.ListenAndServe(r)
- return nil
- }
- func (r *SDHCPRelay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
- pkg, err := r.serveDHCPInternal(pkt, addr)
- return pkg, nil, err
- }
- func (r *SDHCPRelay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
- log.Infof("DHCP Relay Reply TO %s", pkt.CHAddr())
- v, ok := r.cache.Load(pkt.TransactionID())
- if ok {
- r.cache.Delete(pkt.TransactionID())
- val := v.(*SRelayCache)
- udpAddr := &net.UDPAddr{
- IP: pkt.CIAddr(),
- Port: val.srcPort,
- }
- if err := r.guestDHCPConn.SendDHCP(pkt, udpAddr, pkt.CHAddr()); err != nil {
- log.Errorln(err)
- }
- }
- return nil, nil
- }
- func (r *SDHCPRelay) Relay(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
- if addr.IP.Equal(r.ipv4srcAddr) {
- return nil, nil
- }
- log.Infof("Receive DHCP Relay Rquest FROM %s %s", addr.IP, pkt.CHAddr())
- // clean cache first
- var now = time.Now().Add(time.Second * -30)
- r.cache.Range(func(key, value interface{}) bool {
- v := value.(*SRelayCache)
- if v.timer.Before(now) {
- r.cache.Delete(key)
- }
- return true
- })
- // cache pkt info
- r.cache.Store(pkt.TransactionID(), &SRelayCache{
- mac: pkt.CHAddr(),
- srcPort: addr.Port,
- timer: time.Now(),
- })
- pkt.SetGIAddr(r.ipv4srcAddr)
- err := r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil)
- return nil, err
- }
|