配置avahi使用mdns/dns-sd零配置发现samba/smb共享存储:
apt install avahi-daemon
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服务器:
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时会出错:
Static host name smb.haiyun.me.local: avahi_server_add_address failure: Local name collision
可以使用avahi-publish手工发布域名且不添加ip反查域名:
avahi-publish -a -R smb.haiyun.me.local 168.168.168.1
也可以修改systemd service让avahi启动时自动启动avahi-publish:
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
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:
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服务:
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:
{
"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/