1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This is the SMB NIC monitoring module. 30 */ 31 #include <sys/types.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <signal.h> 37 #include <stdio.h> 38 #include <net/if.h> 39 #include <net/route.h> 40 #include <sys/sockio.h> 41 #include <sys/socket.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <fcntl.h> 45 #include <pthread.h> 46 #include <syslog.h> 47 #include <smbsrv/libsmb.h> 48 #include <smbsrv/libsmbns.h> 49 50 static pthread_t smb_nicmon_thread; 51 52 static void smb_nicmon_setup_rtsock(int, int *); 53 static int smb_nicmon_needscan(int); 54 static void *smb_nicmon_daemon(void *); 55 static int smb_nicmon_setup_eventpipe(int *, int *); 56 57 /* Use this to stop monitoring */ 58 static int eventpipe_write = -1; 59 60 /* 61 * Start the nic monitor thread. 62 */ 63 int 64 smb_nicmon_start(void) 65 { 66 int rc = 0; 67 68 if ((rc = smb_nic_init()) != 0) { 69 syslog(LOG_ERR, "NIC monitor failed to initialize (%s)", 70 strerror(errno)); 71 return (rc); 72 } 73 74 rc = pthread_create(&smb_nicmon_thread, NULL, smb_nicmon_daemon, 0); 75 if (rc != 0) { 76 syslog(LOG_ERR, "NIC monitor failed to start (%s)", 77 strerror(errno)); 78 return (rc); 79 } 80 81 return (rc); 82 } 83 84 /* 85 * Stop the nic monitor. 86 */ 87 void 88 smb_nicmon_stop(void) 89 { 90 uchar_t buf = 1; 91 92 if (eventpipe_write < 0) 93 return; 94 95 (void) write(eventpipe_write, &buf, sizeof (buf)); 96 smb_nic_fini(); 97 } 98 99 /* 100 * Call this to do stuff after ifs changed. 101 */ 102 void 103 smb_nicmon_reconfig(void) 104 { 105 char fqdn[MAXHOSTNAMELEN]; 106 boolean_t ddns_enabled; 107 108 ddns_enabled = smb_config_getbool(SMB_CI_DYNDNS_ENABLE); 109 (void) smb_getfqdomainname(fqdn, MAXHOSTNAMELEN); 110 111 /* Clear rev zone before creating if list */ 112 if (ddns_enabled) { 113 if (*fqdn != '\0' && dyndns_clear_rev_zone(fqdn) != 0) { 114 syslog(LOG_ERR, "smb_nicmon_daemon: " 115 "failed to clear DNS reverse lookup zone"); 116 } 117 } 118 119 /* re-initialize NIC table */ 120 if (smb_nic_init() != 0) 121 syslog(LOG_ERR, "smb_nicmon_daemon: " 122 "failed to get NIC information"); 123 124 smb_netbios_name_reconfig(); 125 smb_browser_reconfig(); 126 127 if (ddns_enabled) { 128 if (*fqdn != '\0' && dyndns_update(fqdn, B_FALSE) != 0) { 129 syslog(LOG_ERR, "smb_nicmon_daemon: " 130 "failed to update dynamic DNS"); 131 } 132 } 133 } 134 135 /* 136 * Setup routing socket for getting RTM messages. 137 */ 138 static void 139 smb_nicmon_setup_rtsock(int af, int *s) 140 { 141 int flags; 142 143 *s = socket(PF_ROUTE, SOCK_RAW, af); 144 if (*s == -1) { 145 syslog(LOG_ERR, "smb_nicmon_daemon: failed to " 146 "create routing socket"); 147 return; 148 } 149 if ((flags = fcntl(*s, F_GETFL, 0)) < 0) { 150 syslog(LOG_ERR, "smb_nicmon_daemon: " 151 "failed to fcntl F_GETFL"); 152 (void) close(*s); 153 *s = -1; 154 return; 155 } 156 if ((fcntl(*s, F_SETFL, flags | O_NONBLOCK)) < 0) { 157 syslog(LOG_ERR, "smb_nicmon_daemon: " 158 "failed to fcntl F_SETFL"); 159 (void) close(*s); 160 *s = -1; 161 return; 162 } 163 } 164 165 static int 166 smb_nicmon_needscan(int sock) 167 { 168 int nbytes; 169 int64_t msg[2048 / 8]; 170 struct rt_msghdr *rtm; 171 int need_if_scan = 0; 172 173 /* Read as many messages as possible and try to empty the sockets */ 174 for (;;) { 175 nbytes = read(sock, msg, sizeof (msg)); 176 if (nbytes <= 0) { 177 break; 178 } 179 rtm = (struct rt_msghdr *)msg; 180 if (rtm->rtm_version != RTM_VERSION) { 181 continue; 182 } 183 if (nbytes < rtm->rtm_msglen) { 184 syslog(LOG_DEBUG, "smb_nicmon_daemon: short read: %d " 185 "of %d", nbytes, rtm->rtm_msglen); 186 continue; 187 } 188 189 switch (rtm->rtm_type) { 190 case RTM_NEWADDR: 191 case RTM_DELADDR: 192 case RTM_IFINFO: 193 need_if_scan = 1; 194 break; 195 default: 196 break; 197 } 198 } 199 200 return (need_if_scan); 201 } 202 203 /* 204 * Create pipe for signal delivery and set up signal handlers. 205 */ 206 static int 207 smb_nicmon_setup_eventpipe(int *read_pipe, int *write_pipe) 208 { 209 int fds[2]; 210 211 if ((pipe(fds)) < 0) { 212 syslog(LOG_ERR, "smb_nicmon_daemon: failed to open pipe"); 213 return (1); 214 } 215 *read_pipe = fds[0]; 216 *write_pipe = fds[1]; 217 return (0); 218 } 219 220 /*ARGSUSED*/ 221 static void * 222 smb_nicmon_daemon(void *args) 223 { 224 struct pollfd pollfds[2]; 225 int pollfd_num = 2; 226 int i, nic_changed; 227 /* AF_INET routing socket add AF_INET6 when we support IPv6 */ 228 static int rtsock_v4; 229 static int eventpipe_read = -1; 230 231 /* 232 * Create the global routing socket. We use this to 233 * monitor changes in NIC interfaces. We are only interested 234 * in new inerface addition/deletion and change in UP/DOWN status. 235 */ 236 smb_nicmon_setup_rtsock(AF_INET, &rtsock_v4); 237 if (rtsock_v4 == -1) { 238 syslog(LOG_ERR, "smb_nicmon_daemon: " 239 "cannot open routing socket"); 240 return (NULL); 241 } 242 243 if (smb_nicmon_setup_eventpipe(&eventpipe_read, &eventpipe_write) 244 != 0) { 245 syslog(LOG_ERR, "smb_nicmon_daemon: cannot open event pipes"); 246 return (NULL); 247 } 248 249 /* 250 * Keep listening for activity on any of the sockets. 251 */ 252 for (;;) { 253 nic_changed = 0; 254 pollfds[0].fd = rtsock_v4; 255 pollfds[0].events = POLLIN; 256 pollfds[1].fd = eventpipe_read; 257 pollfds[1].events = POLLIN; 258 if (poll(pollfds, pollfd_num, -1) < 0) { 259 if (errno == EINTR) 260 continue; 261 syslog(LOG_ERR, "smb_nicmon_daemon: " 262 "poll failed with errno %d", errno); 263 break; 264 } 265 for (i = 0; i < pollfd_num; i++) { 266 if ((pollfds[i].fd < 0) || 267 !(pollfds[i].revents & POLLIN)) 268 continue; 269 if (pollfds[i].fd == rtsock_v4) 270 nic_changed = smb_nicmon_needscan(rtsock_v4); 271 if (pollfds[i].fd == eventpipe_read) 272 goto done; 273 } 274 275 /* 276 * If anything changed do refresh our 277 * nic list and other configs. 278 */ 279 if (nic_changed) 280 smb_nicmon_reconfig(); 281 } 282 done: 283 /* Close sockets */ 284 (void) close(rtsock_v4); 285 (void) close(eventpipe_read); 286 (void) close(eventpipe_write); 287 eventpipe_write = -1; 288 return (NULL); 289 } 290