+
    Mjz                     n    R t ^ RIt^ RIt^ RIt^ RItRt^tRtRtR t	Rt
R tRR ltRR	 ltR
 tRR ltR# )u  sshj.tailnet — tailscale peers + MagicDNS name targeting (B12/B16, leaf).

B2 step 2: moved verbatim from sshj_cli.py (single-file era) — no behavior
change. Owns TAILNET_MARK (the muted dot-matrix mark the UI renders for
tailnet rows) because it is the marker this module stamps.
Nu   ⣿u0_a3602222c                    \         P                  ! R4      '       g   R. 3#  \        P                  ! . RORR\        R7      p \
        P                  ! V P                  4      pRpTP                  R. 4       F'  pTP                  R4      '       d   K  RT9  g   K%  Tp M	  . pTP                  R/ 4      P                  4        F  pTP                  R. 4       Uu. uF  pRT9  g   K  TNK  	  ppT'       d   T^ ,          T8X  d   KE  TP                  R	TP                  R
T^ ,          4      RT^ ,          RTP                  R4      ;'       g    RP                  4       R\        TP                  R4      4      RTP                  R4      ;'       g    RP                  4       /4       K  	  Y$3#   \         d    R. 3u # i ; iu upi )u  (self_ip, [peer, ...]) from `tailscale status --json`, or ("", []).

Each peer: {"name", "ip" (first v4), "os", "online", "dnsname"}.
Degrades to ("", []) when tailscale is missing, the call fails, or the
JSON is unparseable — the tailnet is a source, never a crash (C3).	tailscale Tcapture_outputtexttimeoutTailscaleIPsfd:PeernameHostNameiposOSonlineOnlinednsnameDNSNamer   statusz--json)shutilwhich
subprocessrun
TS_TIMEOUTjsonloadsstdout	Exceptionget
startswithvaluesappendlowerboolstrip)rdself_ipr   peerspipss          src/sshj/tailnet.pytailnet_peersr1      s    <<$$2vNN<*.T#-/ JJqxx  GeeNB'}}T""s"}G ( EUU62%%'EE."5G5bBrr5Gc!f'faeeJA7s1vQUU4[..B557QUU8_ 5!%%	"2"8"8b!?!?!AC 	D	 ( >!  2v Hs   A F. 	G(G.G ?G z100.100.100.100c                    V '       g   R# V P                  4       P                  R4      pVP                  R4      ^ ,          # )zPeer DNSName FQDN -> the short MagicDNS name that actually resolves.

MagicDNS serves each node by its FIRST label (e.g. `cw-phone`), so the
short name is the first label of the FQDN; the tailnet domain
(`<tailnet>.ts.net`) is dropped. None/'' -> ''.r   .)r)   rstripsplit)fqdnr   s   & r0   _magicdns_shortr7   =   s3     ::<s#D::c?1    c                   V '       d5   V P                  4       P                  R4      P                  R4      '       g   R# T;'       g*    \        P                  P                  R4      ;'       g    Rp \        V4      ;_uu_ 4       p\        VP                  4       9   d    RRR4       R#  RRR4        \        P                  ! RR	\        T 4      .RR^R
7      pTP                  ^ 8H  ;'       d$    \        TP                  P                  4       4      #   + '       g   i     Lq; i  \         d     Li ; i  \          d     R# i ; i)a  True when the local box can RESOLVE MagicDNS names, so tailnet rows
can target the human-readable name instead of the IP.

Detection (both must hold for a confident True):
  1. self has a `...ts.net` DNSName (we're on a MagicDNS tailnet), AND
  2. resolv.conf lists 100.100.100.100, OR `getent hosts <self-short>`
     resolves (covers systemd-resolved/WSL where the nameserver line
     lives elsewhere).
Falsy self DNSName or a foreign domain => False (never a crash).r3   z.ts.netFSSHJ_RESOLV_CONFz/etc/resolv.confNTgetenthostsr   )r)   r4   endswithr   environr#   openMAGICDNS_NAMESERVERreadOSErrorr   r   r7   
returncoder(   r!   r"   )self_dnsnameresolv_confconffr*   s   &&   r0   magicdns_onrH   I   s    |113::3?HH     "**..);<   	$ZZ1"affh. Z. NNHg|/LM*.T1F||q ;;T!((..*:%;; Z    sN   3D( D!D( ,D( 5;D9 1#D9 D%	 D( %D( (D65D69EEc                    V P                  R4      ;'       g,    V P                  R4      ;'       g    V P                  RR4      pV'       d&   V P                  R4      '       d   V R,           RV 2# V# )a#  The ssh ADDRESS for a host: its MagicDNS short name when we can
resolve it (B16), else the raw hostname/IP. `with_user` adds user@
(connect uses it; probes stay bare so ssh tries both keys). Everything
that builds an ssh address goes through here so the IP-fallback stays
exact B12 behavior.magicdnshostnamealiasr   user@)r#   )h	with_userhosts   && r0   ssh_hostrR   g   s_     55GGj 1GGQUU7B5GDQUU6]]F)AdV$$Kr8   c                 L   \         P                  ! R4      '       g   R#  \        P                  ! . RORR\        R7      p \
        P                  ! V P                  4      pVP                  R4      ;'       g    / P                  R4      ;'       g    R#   \         d     R# i ; i)zOur own MagicDNS FQDN from `tailscale status --json` (Self.DNSName),
or "". One bounded call; degrades to "" like the rest of B12/B16.r   r   Tr   Selfr   r   )
r   r   r   r   r   r   r    r!   r#   r"   )r*   r+   s     r0   rD   rD   s   s     <<$$NN<*.T#-/ JJqxx f##((399r9 s   AB 8B B B#"B#c                   / pV  F,  pVP                  R4      ;'       g    RpV'       g   K(  WTV&   K.  	  \        V 4      p. pV F  p	V	R,          p
VP                  V
4      pVe   RVR&   K(  V	R,          R8X  d   \        \        rMRRrYR9  d   R	V 2MR,           pV'       d   V R
V 2pRV	R,          RV	R,          R,           RVRV
RVRRRVRRRRRR/
pV'       d6   V	P                  R4      '       d   \	        V	R,          4      pV'       d   WR&   VP                  V4       VP                  V4       WTV
&   K  	  Wx3# )u  Fold tailnet peers into the pool (B12/B16) — dedupe, never duplicate.

1. A peer whose IP is already a known row gets the `tailnet` flag
   (the UI draws the mark in the name cell's reserved last cell —
   the data stays clean; NO new row, anti-redundancy).
2. A peer matching NO row becomes a new `Name·ts` row: android peers
   take the Termux sshd convention (user:port); everyone else the
   bare-IP floor (ssh's own defaults). Heuristic rows are the honest
   fallback — the checker will tell the truth once it probes them.
3. (B16) When magicdns_on and the peer carries a DNSName, the row gets
   a `magicdns` short name — the ssh TARGETS use it (ssh_host), the
   displayed target + dedupe keep the IP. No DNSName / off => exact B12.
Returns (hosts, newly_discovered). The TAILNET_MARK is a muted
dot-matrix glyph in the NAME column's reserved last cell (ui renders
it from the `tailnet` flag, so truncation can never eat it).rK   r   r   Ttailnetr   android22r   rN   rL   r   dispu   ·tsrM   portr
   0targetsrctssrc_pathr   rJ   )r   rX   )r#   listTERMUX_SSH_USERTERMUX_SSH_PORTr7   r&   )r<   r,   r-   rH   by_iprO   hnoutnewr.   r   existingrM   rZ   tgtshorts   &&&&            r0   merge_tailnetrj      sN     EUU:$$"2"I  u+C
CtW99R="&HY T7i(/$T$j"8avJbAF!C5/Cai6V);T:r64XsE4It5 155++#AiL1E %*

1

1b	9 : 8Or8   )N)F)__doc__r   r   r   r   TAILNET_MARKr   ra   rb   r1   r@   r7   rH   rR   rD   rj    r8   r0   <module>rn      sW     	    
B ( 	<	4r8   