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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
--- a/Clients/Makefile
+++ b/Clients/Makefile
@@ -42,7 +42,7 @@ TARGETS = build/dns-sd build/dns-sd64
LIBS =
else
TARGETS = build/dns-sd
-LIBS = -L../mDNSPosix/$(BUILDDIR)/ -ldns_sd
+LIBS ?= -L../mDNSPosix/$(BUILDDIR)/ -ldns_sd
endif
all: $(TARGETS)
--- a/mDNSPosix/PosixDaemon.c
+++ b/mDNSPosix/PosixDaemon.c
@@ -38,6 +38,11 @@
#include <pwd.h>
#include <sys/types.h>
#include <sys/socket.h>
+#ifdef __linux__
+#include <sys/capability.h> /* !!! We require libcap-dev for this. Oh well. */
+/* prctl is required to enable inheriting of capabilities across setuid */
+#include <sys/prctl.h>
+#endif /* __linux__ */
#if __APPLE__
#undef daemon
@@ -194,6 +199,18 @@ int main(int argc, char **argv)
Reconfigure(&mDNSStorage);
+#ifdef __linux__
+ /*
+ * SO_BINDTODEVICE is privileged operation; however, we can get
+ * around it using capabilities instead of remaining root.
+ */
+ if (mStatus_NoError == err)
+ {
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0)
+ perror("prctl PR_SET_KEEPCAPS");
+ }
+#endif /* __linux__ */
+
// Now that we're finished with anything privileged, switch over to running as "nobody"
if (mStatus_NoError == err)
{
@@ -209,6 +226,21 @@ int main(int argc, char **argv)
{
LogMsg("WARNING: mdnsd continuing as root because setuid to \"nobody\" failed with %s", strerror(errno));
}
+#ifdef __linux__
+ struct __user_cap_header_struct ch;
+ struct __user_cap_data_struct cd[_LINUX_CAPABILITY_U32S_3];
+
+ memset(&ch, 0, sizeof(ch));
+ ch.version = _LINUX_CAPABILITY_VERSION_3;
+ ch.pid = getpid();
+ memset(&cd[0], 0, sizeof(cd));
+ /* CAP_NET_RAW is required to use SO_BINDTODEVICE */
+ int caps = CAP_TO_MASK(CAP_NET_RAW);
+ cd[0].permitted = caps;
+ cd[0].effective = caps;
+ if (capset(&ch, &cd[0]) < 0)
+ perror("capset");
+#endif /* __linux__ */
}
else
{
@@ -216,6 +248,11 @@ int main(int argc, char **argv)
}
}
+#ifdef __linux__
+ if (mStatus_NoError == err)
+ err = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage);
+#endif /* __linux__ */
+
if (mStatus_NoError == err)
err = MainLoop(&mDNSStorage);
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1223,6 +1223,29 @@ mDNSlocal int SetupSocket(struct sockadd
if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
}
+#ifdef __linux__
+#ifdef SO_BINDTODEVICE
+ if (err == 0 && interfaceIndex)
+ {
+ char ifname[IFNAMSIZ];
+ if (if_indextoname(interfaceIndex, ifname))
+ {
+ err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+ if (err < 0)
+ {
+ err = errno;
+ perror("setsockopt - SO_BINDTODEVICE");
+ }
+ }
+ else
+ {
+ err = errno;
+ perror("if_indextoname");
+ }
+ }
+#endif /* SO_BINDTODEVICE */
+#endif /* __linux__ */
+
// And start listening for packets
if (err == 0)
{
@@ -1298,6 +1321,29 @@ mDNSlocal int SetupSocket(struct sockadd
if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
}
+#ifdef __linux__
+#ifdef SO_BINDTODEVICE
+ if (err == 0 && interfaceIndex)
+ {
+ char ifname[IFNAMSIZ];
+ if (if_indextoname(interfaceIndex, ifname))
+ {
+ err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+ if (err < 0)
+ {
+ err = errno;
+ perror("setsockopt - SO_BINDTODEVICE");
+ }
+ }
+ else
+ {
+ err = errno;
+ perror("if_indextoname");
+ }
+ }
+#endif /* SO_BINDTODEVICE */
+#endif /* __linux__ */
+
// And start listening for packets
if (err == 0)
{
@@ -1899,8 +1945,12 @@ mDNSexport mStatus mDNSPlatformInit(mDNS
if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
#endif
+ // In Linux case, we can't set up sockets with different owner -
+ // it blows up SO_REUSEPORT. So we do this step bit later.
+#ifndef __linux__
// Tell mDNS core about the network interfaces on this machine.
if (err == mStatus_NoError) err = SetupInterfaceList(m);
+#endif /* !__linux__ */
// Tell mDNS core about DNS Servers
mDNS_Lock(m);
--- a/mDNSShared/dnsextd_parser.y
+++ b/mDNSShared/dnsextd_parser.y
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+%parse-param { void *context }
+
%{
#include <stdio.h>
#include <stdlib.h>
@@ -23,7 +25,7 @@
#include "DebugServices.h"
#include "dnsextd.h"
-void yyerror( const char* error );
+void yyerror( void* context, const char* error );
int yylex(void);
@@ -409,7 +411,7 @@ int yywrap(void);
extern int yylineno;
-void yyerror( const char *str )
+void yyerror( void* context, const char *str )
{
fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
}
|