1 /*
2 Copyright 2020 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <findhub.h>
26 #include <cleanup.h>
27 #include <string_lib.h>
28 #include <misc_lib.h>
29 #include <logging.h>
30 #include <alloc.h>
31
32 List *hublist = NULL;
33
34 static void CleanupDlClose(void);
35 static int CompareHosts(const void *a, const void *b);
36
client_callback(AvahiClient * c,AvahiClientState state,AVAHI_GCC_UNUSED void * userdata)37 void client_callback(AvahiClient *c,
38 AvahiClientState state,
39 AVAHI_GCC_UNUSED void *userdata)
40 {
41 assert(c);
42
43 if (state == AVAHI_CLIENT_FAILURE)
44 {
45 Log(LOG_LEVEL_ERR, "Server connection failure '%s'", avahi_strerror_ptr(avahi_client_errno_ptr(c)));
46 avahi_simple_poll_quit_ptr(spoll);
47 }
48 }
49
browse_callback(AvahiServiceBrowser * b,AvahiIfIndex interface,AvahiProtocol protocol,AvahiBrowserEvent event,const char * name,const char * type,const char * domain,AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,void * userdata)50 void browse_callback(AvahiServiceBrowser *b,
51 AvahiIfIndex interface,
52 AvahiProtocol protocol,
53 AvahiBrowserEvent event,
54 const char *name,
55 const char *type,
56 const char *domain,
57 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
58 void *userdata)
59 {
60 AvahiClient *c = userdata;
61 assert(b);
62
63 switch(event)
64 {
65 case AVAHI_BROWSER_FAILURE:
66 Log(LOG_LEVEL_ERR, "Avahi browser error '%s'", avahi_strerror_ptr(avahi_client_errno_ptr(avahi_service_browser_get_client_ptr(b))));
67 avahi_simple_poll_quit_ptr(spoll);
68 return;
69
70 case AVAHI_BROWSER_NEW:
71 if ( !(avahi_service_resolver_new_ptr(c, interface, protocol, name,
72 type, domain, AVAHI_PROTO_UNSPEC, 0,
73 (AvahiServiceResolverCallback) resolve_callback, c)) )
74 {
75 Log(LOG_LEVEL_ERR, "Failed to resolve service '%s', error '%s'", name, avahi_strerror_ptr(avahi_client_errno_ptr(c)));
76 }
77 break;
78
79 case AVAHI_BROWSER_REMOVE:
80 break;
81
82 case AVAHI_BROWSER_ALL_FOR_NOW:
83 avahi_simple_poll_quit_ptr(spoll);
84 break;
85
86 case AVAHI_BROWSER_CACHE_EXHAUSTED:
87 break;
88 }
89 }
90
resolve_callback(AvahiServiceResolver * r,AVAHI_GCC_UNUSED AvahiIfIndex interface,AVAHI_GCC_UNUSED AvahiProtocol protocol,AvahiResolverEvent event,const char * name,const char * type,const char * domain,const char * host_name,const AvahiAddress * address,uint16_t port,AVAHI_GCC_UNUSED AvahiStringList * txt,AVAHI_GCC_UNUSED AvahiLookupFlags flags,AVAHI_GCC_UNUSED void * userdata)91 void resolve_callback(AvahiServiceResolver *r,
92 AVAHI_GCC_UNUSED AvahiIfIndex interface,
93 AVAHI_GCC_UNUSED AvahiProtocol protocol,
94 AvahiResolverEvent event,
95 const char *name,
96 const char *type,
97 const char *domain,
98 const char *host_name,
99 const AvahiAddress *address,
100 uint16_t port,
101 AVAHI_GCC_UNUSED AvahiStringList *txt,
102 AVAHI_GCC_UNUSED AvahiLookupFlags flags,
103 AVAHI_GCC_UNUSED void* userdata)
104 {
105 HostProperties *hostprop = xcalloc(1, sizeof(HostProperties));
106 assert(r);
107 char a[AVAHI_ADDRESS_STR_MAX];
108 switch(event)
109 {
110 case AVAHI_RESOLVER_FAILURE:
111 Log(LOG_LEVEL_ERR, "In Avahi resolver, failed to resolve service '%s' of type '%s' in domain '%s' (error: '%s')",
112 name, type, domain, avahi_strerror_ptr(avahi_client_errno_ptr(avahi_service_resolver_get_client_ptr(r))));
113 break;
114
115 case AVAHI_RESOLVER_FOUND:
116 avahi_address_snprint_ptr(a, sizeof(a), address);
117
118 strlcpy(hostprop->Hostname, host_name, 4096);
119 strlcpy(hostprop->IPAddress, a, AVAHI_ADDRESS_STR_MAX);
120 hostprop->Port = port;
121 ListAppend(hublist, hostprop);
122 break;
123 }
124
125 avahi_service_resolver_free_ptr(r);
126 }
127
PrintList(List * list)128 void PrintList(List *list)
129 {
130 ListIterator *i = NULL;
131
132 i = ListIteratorGet(list);
133 if (!i)
134 {
135 ProgrammingError("Unable to get iterator for hub list");
136 return;
137 }
138
139 do
140 {
141 HostProperties *hostprop = (HostProperties *)ListIteratorData(i);
142
143 Log(LOG_LEVEL_NOTICE, "CFEngine Policy Server: hostname '%s', IP address '%s', port %d",
144 hostprop->Hostname, hostprop->IPAddress, hostprop->Port);
145 } while (ListIteratorNext(i) != -1);
146
147 ListIteratorDestroy(&i);
148 }
149
ListHubs(List ** list)150 int ListHubs(List **list)
151 {
152 AvahiClient *client = NULL;
153 AvahiServiceBrowser *sb = NULL;
154 int error;
155
156 hublist = ListNew(&CompareHosts, NULL, &free);
157 if (!hublist)
158 {
159 return -1;
160 }
161
162 spoll = NULL;
163 avahi_handle = NULL;
164
165 RegisterCleanupFunction(&CleanupDlClose);
166
167 if (loadavahi() == -1)
168 {
169 Log(LOG_LEVEL_ERR, "Avahi was not found");
170 return -1;
171 }
172
173 if (!(spoll = avahi_simple_poll_new_ptr()))
174 {
175 Log(LOG_LEVEL_ERR, "Failed to create simple poll object.");
176
177 if (spoll)
178 {
179 avahi_simple_poll_free_ptr(spoll);
180 }
181 return -1;
182 }
183
184 client = avahi_client_new_ptr(avahi_simple_poll_get_ptr(spoll), 0, client_callback, NULL, &error);
185
186 if (!client)
187 {
188 Log(LOG_LEVEL_ERR, "Failed to create client '%s'", avahi_strerror_ptr(error));
189
190 if (client)
191 {
192 avahi_client_free_ptr(client);
193 }
194
195 if (spoll)
196 {
197 avahi_simple_poll_free_ptr(spoll);
198 }
199
200 return -1;
201 }
202
203 if (!(sb = avahi_service_browser_new_ptr(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_cfenginehub._tcp", NULL, 0, browse_callback, client)))
204 {
205 Log(LOG_LEVEL_ERR, "Failed to create service browser '%s'", avahi_strerror_ptr(avahi_client_errno_ptr(client)));
206
207 if (spoll)
208 {
209 avahi_simple_poll_free_ptr(spoll);
210 }
211
212 if (client)
213 {
214 avahi_client_free_ptr(client);
215 }
216
217 if (sb)
218 {
219 avahi_service_browser_free_ptr(sb);
220 }
221
222 return -1;
223 }
224
225 avahi_simple_poll_loop_ptr(spoll);
226
227 if (sb)
228 avahi_service_browser_free_ptr(sb);
229 if (client)
230 avahi_client_free_ptr(client);
231 if (spoll)
232 avahi_simple_poll_free_ptr(spoll);
233
234 *list = hublist;
235
236 return ListCount(*list);
237 }
238
CleanupDlClose(void)239 static void CleanupDlClose(void)
240 {
241 if (avahi_handle != NULL)
242 {
243 dlclose(avahi_handle);
244 }
245 }
246
CompareHosts(const void * a,const void * b)247 static int CompareHosts(const void *a, const void *b)
248 {
249 return StringSafeCompare(((HostProperties*)a)->Hostname, ((HostProperties*)b)->Hostname);
250 }
251