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 2007 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_setup_rtsock(int, int *); 53 static int smb_nics_changed(int); 54 static void *smb_nicmonitor(void *); 55 static int smb_setup_eventpipe(int *, int *); 56 static void smb_process_nic_change(); 57 58 /* Use this to stop monitoring */ 59 static int eventpipe_write = -1; 60 61 /* 62 * Start the nic monitor thread. 63 */ 64 int 65 smb_nicmon_start(void) 66 { 67 int rc = 0; 68 69 smb_nic_build_info(); 70 rc = pthread_create(&smb_nicmon_thread, NULL, smb_nicmonitor, 0); 71 if (rc != 0) { 72 syslog(LOG_ERR, "smb_nicmonitor: " 73 "NIC monitoring failed to start: %s", strerror(errno)); 74 return (rc); 75 } 76 return (rc); 77 } 78 79 /* 80 * Stop the nic monitor. 81 */ 82 void 83 smb_nicmon_stop(void) 84 { 85 uchar_t buf = 1; 86 87 if (eventpipe_write < 0) 88 return; 89 90 (void) write(eventpipe_write, &buf, sizeof (buf)); 91 } 92 93 /* 94 * Setup routing socket for getting RTM messages. 95 */ 96 static void 97 smb_setup_rtsock(int af, int *s) 98 { 99 int flags; 100 101 *s = socket(PF_ROUTE, SOCK_RAW, af); 102 if (*s == -1) { 103 syslog(LOG_ERR, "smb_setup_rtsock: failed to " 104 "create routing socket"); 105 return; 106 } 107 if ((flags = fcntl(*s, F_GETFL, 0)) < 0) { 108 syslog(LOG_ERR, "smb_setup_rtsock: failed to fcntl F_GETFL"); 109 (void) close(*s); 110 *s = -1; 111 return; 112 } 113 if ((fcntl(*s, F_SETFL, flags | O_NONBLOCK)) < 0) { 114 syslog(LOG_ERR, "smb_setup_rtsock: failed to fcntl F_SETFL"); 115 (void) close(*s); 116 *s = -1; 117 return; 118 } 119 } 120 121 static int 122 smb_nics_changed(int sock) 123 { 124 int nbytes; 125 int64_t msg[2048 / 8]; 126 struct rt_msghdr *rtm; 127 int need_if_scan = 0; 128 129 /* Read as many messages as possible and try to empty the sockets */ 130 for (;;) { 131 nbytes = read(sock, msg, sizeof (msg)); 132 if (nbytes <= 0) { 133 break; 134 } 135 rtm = (struct rt_msghdr *)msg; 136 if (rtm->rtm_version != RTM_VERSION) { 137 continue; 138 } 139 if (nbytes < rtm->rtm_msglen) { 140 syslog(LOG_DEBUG, "smb_nicmonitor: short read: %d " 141 "of %d", nbytes, rtm->rtm_msglen); 142 continue; 143 } 144 145 switch (rtm->rtm_type) { 146 case RTM_NEWADDR: 147 case RTM_DELADDR: 148 case RTM_IFINFO: 149 need_if_scan = 1; 150 break; 151 default: 152 break; 153 } 154 } 155 156 return (need_if_scan); 157 } 158 159 /* 160 * Create pipe for signal delivery and set up signal handlers. 161 */ 162 static int 163 smb_setup_eventpipe(int *read_pipe, int *write_pipe) 164 { 165 int fds[2]; 166 167 if ((pipe(fds)) < 0) { 168 syslog(LOG_ERR, "smb_nicmonitor: failed to open pipe"); 169 return (1); 170 } 171 *read_pipe = fds[0]; 172 *write_pipe = fds[1]; 173 return (0); 174 } 175 176 /* 177 * Call this to do stuff after ifs changed. 178 */ 179 static void 180 smb_process_nic_change() 181 { 182 int ddns_enabled; 183 184 smb_config_rdlock(); 185 ddns_enabled = smb_config_getyorn(SMB_CI_DYNDNS_ENABLE); 186 smb_config_unlock(); 187 188 /* Clear rev zone before creating if list */ 189 if (ddns_enabled) { 190 if (dyndns_clear_rev_zone() != 0) { 191 syslog(LOG_ERR, "smb_nicmonitor: " 192 "failed to clear DNS reverse lookup zone"); 193 } 194 } 195 196 /* re-initialize NIC table */ 197 smb_nic_build_info(); 198 199 smb_netbios_name_reconfig(); 200 201 if (ddns_enabled) { 202 if (dyndns_update() != 0) { 203 syslog(LOG_ERR, "smb_nicmonitor: " 204 "failed to update dynamic DNS"); 205 } 206 } 207 } 208 209 /*ARGSUSED*/ 210 static void * 211 smb_nicmonitor(void *args) 212 { 213 struct pollfd pollfds[2]; 214 int pollfd_num = 2; 215 int i, nic_changed; 216 /* AF_INET routing socket add AF_INET6 when we support IPv6 */ 217 static int rtsock_v4; 218 static int eventpipe_read = -1; 219 220 /* 221 * Create the global routing socket. We use this to 222 * monitor changes in NIC interfaces. We are only interested 223 * in new inerface addition/deletion and change in UP/DOWN status. 224 */ 225 smb_setup_rtsock(AF_INET, &rtsock_v4); 226 if (rtsock_v4 == -1) { 227 syslog(LOG_ERR, "smb_nicmonitor: cannot open routing socket"); 228 return (NULL); 229 } 230 if (smb_setup_eventpipe(&eventpipe_read, &eventpipe_write) != 0) { 231 syslog(LOG_ERR, "smb_nicmonitor: cannot open event pipes"); 232 return (NULL); 233 } 234 235 /* 236 * Keep listening for activity on any of the sockets. 237 */ 238 for (;;) { 239 nic_changed = 0; 240 pollfds[0].fd = rtsock_v4; 241 pollfds[0].events = POLLIN; 242 pollfds[1].fd = eventpipe_read; 243 pollfds[1].events = POLLIN; 244 if (poll(pollfds, pollfd_num, -1) < 0) { 245 if (errno == EINTR) 246 continue; 247 syslog(LOG_ERR, "smb_nicmonitor: " 248 "poll failed with errno %d", errno); 249 break; 250 } 251 for (i = 0; i < pollfd_num; i++) { 252 if ((pollfds[i].fd < 0) || 253 !(pollfds[i].revents & POLLIN)) 254 continue; 255 if (pollfds[i].fd == rtsock_v4) 256 nic_changed = smb_nics_changed(rtsock_v4); 257 if (pollfds[i].fd == eventpipe_read) 258 goto done; 259 } 260 261 /* 262 * If anything changed do refresh our 263 * nic list and other configs. 264 */ 265 if (nic_changed) 266 smb_process_nic_change(); 267 } 268 done: 269 /* Close sockets */ 270 (void) close(rtsock_v4); 271 (void) close(eventpipe_read); 272 (void) close(eventpipe_write); 273 eventpipe_write = -1; 274 return (NULL); 275 } 276