code: func NewIPHAConn(laddr, raddr net.IP) (HAConn, error) {
  	sendConn, err := IPConn(laddr, raddr)
  	if err != nil {
  		return nil, err
  	}
  
  	// For IPv6 unicast and multicast, and for IPv4 unicast, we can use the same IPConn for both
  	// sending and receiving. For IPv4 multicast, we need a separate listener for receiving.
  	recvConn := sendConn
  	if raddr.IsMulticast() {
  		if raddr.To4() != nil {
  			log.Infof("Using IPv4 multicast")
  			if recvConn, err = ListenMulticastIPv4(raddr, laddr); err != nil {
  				return nil, err
  			}
  		} else {
  			log.Infof("Using IPv6 multicast")
  			if err = JoinMulticastIPv6(recvConn, raddr, laddr); err != nil {
  				return nil, err
  			}
  		}
  	}
  
  	return &IPHAConn{
  		sendConn: sendConn,
  		recvConn: recvConn,
  		laddr:    laddr,
  		raddr:    raddr,
  	}, nil
  }
docs: // NewIPHAConn creates a new IPHAConn.