PeerForIP returns the Node in the wireguard config that's responsible for handling the given IP address. If none is found in the wireguard config but one is found in the netmap, it's described in an error. peerForIP acquires both e.mu and e.wgLock, but neither at the same time.
(ip netip.Addr)
| 1538 | // peerForIP acquires both e.mu and e.wgLock, but neither at the same |
| 1539 | // time. |
| 1540 | func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) { |
| 1541 | e.mu.Lock() |
| 1542 | nm := e.netMap |
| 1543 | e.mu.Unlock() |
| 1544 | |
| 1545 | if !ip.IsValid() { |
| 1546 | // Treat invalid IPs as just a mutex probe to detect deadlocks. |
| 1547 | // TODO(bradfitz): extend the Engine interface to have an explicit method for |
| 1548 | // this purpose, instead of overloading PeerForIP with this special case. |
| 1549 | // But I'd rather do that at the beginning of a dev cycle. |
| 1550 | e.wgLock.Lock() |
| 1551 | defer e.wgLock.Unlock() |
| 1552 | return ret, false |
| 1553 | } |
| 1554 | |
| 1555 | if nm == nil { |
| 1556 | return ret, false |
| 1557 | } |
| 1558 | |
| 1559 | // Check for exact matches before looking for subnet matches. |
| 1560 | // TODO(bradfitz): add maps for these. on NetworkMap? |
| 1561 | for _, p := range nm.Peers { |
| 1562 | for i := range p.Addresses().Len() { |
| 1563 | a := p.Addresses().At(i) |
| 1564 | if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) { |
| 1565 | return PeerForIP{Node: p, Route: a}, true |
| 1566 | } |
| 1567 | } |
| 1568 | } |
| 1569 | addrs := nm.GetAddresses() |
| 1570 | for i := range addrs.Len() { |
| 1571 | if a := addrs.At(i); a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) { |
| 1572 | return PeerForIP{Node: nm.SelfNode, IsSelf: true, Route: a}, true |
| 1573 | } |
| 1574 | } |
| 1575 | |
| 1576 | e.wgLock.Lock() |
| 1577 | defer e.wgLock.Unlock() |
| 1578 | |
| 1579 | // TODO(bradfitz): this is O(n peers). Add ART to netaddr? |
| 1580 | var best netip.Prefix |
| 1581 | var bestKey key.NodePublic |
| 1582 | for _, p := range e.lastCfgFull.Peers { |
| 1583 | for _, cidr := range p.AllowedIPs { |
| 1584 | if !cidr.Contains(ip) { |
| 1585 | continue |
| 1586 | } |
| 1587 | if !best.IsValid() || cidr.Bits() > best.Bits() { |
| 1588 | best = cidr |
| 1589 | bestKey = p.PublicKey |
| 1590 | } |
| 1591 | } |
| 1592 | } |
| 1593 | // And another pass. Probably better than allocating a map per peerForIP |
| 1594 | // call. But TODO(bradfitz): add a lookup map to netmap.NetworkMap. |
| 1595 | if !bestKey.IsZero() { |
| 1596 | for _, p := range nm.Peers { |
| 1597 | if p.Key() == bestKey { |
no test coverage detected