配置avahi使用mdns/dns-sd零配置发现samba/smb共享存储:
1 | apt install avahi-daemon |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | cat <<EOF > /etc/avahi/services/smb .service <?xml version="1.0" standalone='no'?> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">Samba</name> <service> <type>_smb._tcp</type> <host-name>smb.haiyun.me.local</host-name> <port>445</port> <txt-record>path=/share</txt-record> <txt-record>u=guest</txt-record> <txt-record>p=pass</txt-record> </service> </service-group> EOF echo '192.168.168.1 smb.haiyun.me.local' >> /etc/avahi/hosts |
ftp服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | cat <<EOF > /etc/avahi/services/ftp .service <?xml version="1.0" standalone='no'?> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">FTP</name> <service> <type>_ftp._tcp</type> <host-name>ftp.haiyun.me.local</host-name> <port>21</port> <txt-record>path=/share</txt-record> <txt-record>u=guest</txt-record> <txt-record>p=pass</txt-record> </service> </service-group> EOF echo '192.168.168.2 ftp.haiyun.me.local' >> /etc/avahi/hosts |
注意:
1.host-name可使用FQDN标准域名,但是smb有的客户端不识别。
2.avahi默认会为hosts内目标ip添加反查域名,所以当在/etc/avahi/hosts内添加多个域名指向同一ip时会出错:
1 | Static host name smb.haiyun.me.local: avahi_server_add_address failure: Local name collision |
可以使用avahi-publish手工发布域名且不添加ip反查域名:
1 | avahi-publish -a -R smb.haiyun.me. local 168.168.168.1 |
也可以修改systemd service让avahi启动时自动启动avahi-publish:
1 2 3 4 5 6 7 | apt install avahi-utils cat <<EOF > /usr/local/bin/avahi-host .sh #!/bin/bash /usr/bin/avahi-publish -a -R smb.haiyun.me.local 168.168.168.1 > /dev/null 2>&1 & EOF chmod +x /usr/local/bin/avahi-host .sh sed -i '/ExecStart/aExecStartPost=\/usr\/local\/bin\/avahi-host\.sh' /lib/systemd/system/avahi-daemon .service |
1 2 3 4 | systemctl daemon-reload systemctl restart avahi-daemon.service #手工修改添加ExecStartPost=/usr/local/bin/avahi-host.sh #systemctl edit --full avahi-daemon.service |
使用dig测试mdns/dns-sd:
1 2 3 4 5 6 7 | dig -p 5353 @224.0.0.251 ftp .haiyun.me. local dig -p 5353 @224.0.0.251 _smb._tcp. local ptr dns-sd -B _services._dns-sd._udp dns-sd -B _smb._tcp dns-sd -Z _smb._tcp dns-sd -Q smb.haiyun.me. local dns-sd -Q smb.haiyun.me. local aaaa |
当同一ip有多个服务时也可使用基于golang dnssd的mdns/dns-sd服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | package main import ( "context" "encoding/json" "fmt" "github.com/brutella/dnssd" "net" "os" "os/signal" "time" ) type service struct { Name string Type string Domain string Host string Ips [] string Port int Text map [ string ] interface {} } type config struct { Service []service } func main() { cfg_str, err := os.ReadFile( "config.json" ) if err != nil { fmt.Println( "load config file error:" , err) os.Exit(1) } var cfg config err = json.Unmarshal(cfg_str, &cfg) if err != nil { fmt.Println( "decode json err:" , err) os.Exit(1) } if resp, err := dnssd.NewResponder(); err != nil { fmt.Println(err) } else { for _, v := range cfg.Service { var ips []net.IP for _, ip := range v.Ips { ips = append (ips, net.ParseIP(ip)) } text := make ( map [ string ] string ) for key, value := range v.Text { text[key] = fmt.Sprintf( "%v" , value) } sd_cfg := dnssd.Config{ Name: v.Name, Type: v.Type, Domain: v.Domain, Host: v.Host, IPs: ips, Port: v.Port, Text: text, } srv, err := dnssd.NewService(sd_cfg) if err != nil { fmt.Println(err) } go func () { time.Sleep(1 * time.Second) handle, err := resp.Add(srv) if err != nil { fmt.Println(err) } else { fmt.Printf( "%s Got a reply for service %s: Name now registered and active\n" , time.Now().Format( "2006-01-02 15:04:05" ), handle.Service().ServiceInstanceName()) } }() } ctx, cancel := context.WithCancel(context.Background()) defer cancel() go func () { stop := make ( chan os.Signal, 1) signal.Notify(stop, os.Interrupt) select { case <-stop: cancel() } }() err = resp.Respond(ctx) if err != nil { fmt.Println(err) } } } |
配置文件保存到同目录config.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | { "service" :[ { "name" : "Samba" , "type" : "_smb._tcp" , "domain" : "local" , "host" : "smb.haiyun.me" , "ips" :[ "10.0.0.1" , "fdb2:808c:d0ef:0:20c:29ff:fe7c:264d" ], "port" : 445 , "text" :{ "u" : "user" , "p" : "pass" , "path" : "/share" } }, { "name" : "Ftp" , "type" : "_ftp._tcp" , "domain" : "local" , "host" : "ftp.haiyun.me" , "ips" :[ "10.0.0.1" , "fdb2:808c:d0ef:0:20c:29ff:fe7c:264d" ], "port" : 21 , "text" :{ "u" : "user" , "p" : "pass" , "path" : "/share" } } ] } |
更多服务类型及参数见:
http://www.dns-sd.org/ServiceTypes.html
本地多个不同网段mdns中继:
https://www.haiyun.me/archives/1439.html
参考:
https://github.com/brutella/dnssd
https://kodi.wiki/view/Avahi_Zeroconf
https://linux.die.net/man/5/avahi.service
https://github.com/lathiat/avahi/issues/40
https://pi3g.com/2019/04/10/avahi-how-to-assign-several-local-names-to-same-ip/