@@ -36,6 +36,21 @@ func ParseSSHConfig(configPath string) ([]SSHHost, error) {
3636 configPath = filepath .Join (home , ".ssh" , "config" )
3737 }
3838
39+ visited := make (map [string ]bool )
40+ return parseSSHConfigRecursive (configPath , visited )
41+ }
42+
43+ func parseSSHConfigRecursive (configPath string , visited map [string ]bool ) ([]SSHHost , error ) {
44+ absPath , err := filepath .Abs (configPath )
45+ if err != nil {
46+ return nil , err
47+ }
48+
49+ if visited [absPath ] {
50+ return nil , nil
51+ }
52+ visited [absPath ] = true
53+
3954 file , err := os .Open (configPath )
4055 if err != nil {
4156 return nil , err
@@ -61,6 +76,29 @@ func ParseSSHConfig(configPath string) ([]SSHHost, error) {
6176 key := strings .ToLower (parts [0 ])
6277 value := strings .Join (parts [1 :], " " )
6378
79+ if key == "include" {
80+ includePath := expandPath (value )
81+
82+ if ! filepath .IsAbs (includePath ) {
83+ configDir := filepath .Dir (configPath )
84+ includePath = filepath .Join (configDir , includePath )
85+ }
86+
87+ matches , err := filepath .Glob (includePath )
88+ if err != nil {
89+ continue
90+ }
91+
92+ for _ , match := range matches {
93+ includedHosts , err := parseSSHConfigRecursive (match , visited )
94+ if err != nil {
95+ continue
96+ }
97+ hosts = append (hosts , includedHosts ... )
98+ }
99+ continue
100+ }
101+
64102 if key == "host" {
65103 if currentHost != nil && ! strings .Contains (currentHost .Name , "*" ) && ! strings .Contains (currentHost .Name , "?" ) {
66104 hosts = append (hosts , * currentHost )
0 commit comments