1: #ifndef lint 2: static char *RCSid = "$Source: /usr/users/louie/ntp/RCS/ntp_sock.c,v $ $Revision: 3.4.1.3 $ $Date: 89/05/18 18:28:20 $"; 3: #endif 4: 5: /* 6: * $Log: ntp_sock.c,v $ 7: * Revision 3.4.1.3 89/05/18 18:28:20 louie 8: * In ntp_sock.c, change the order that the bind() call is done for each socket. 9: * It turns out that if you have the Multicast code installed, incoming packets 10: * will be delived to the *first* socket that matches. It also turns out that 11: * when binding sockets, the first one bound is the last on checked, so we want 12: * to bind the wildcard socket first. 13: * 14: * Revision 3.4.1.2 89/04/07 19:07:46 louie 15: * Deleted unused variables in ntp_sock.c 16: * 17: * Revision 3.4.1.1 89/03/22 18:31:20 louie 18: * patch3: Use new RCS headers. 19: * 20: * Revision 3.4 89/03/17 18:37:09 louie 21: * Latest test release. 22: * 23: * Revision 3.3 89/03/15 14:19:53 louie 24: * New baseline for next release. 25: * 26: * Revision 3.2.1.1 89/03/10 11:30:41 louie 27: * 1 28: * 29: * Revision 3.2 89/03/07 18:26:26 louie 30: * New version of UNIX NTP daemon based on the 6 March 1989 draft of the new 31: * NTP protocol specification. This version has a bunch of bugs fixes and 32: * new algorithms which were discussed on the NTP mailing list over the past 33: * few weeks. 34: * 35: * Revision 3.1.1.1 89/02/15 08:56:28 louie 36: * *** empty log message *** 37: * 38: * 39: * Revision 3.1 89/01/30 14:43:12 louie 40: * Second UNIX NTP test release. 41: * 42: * Revision 3.0 88/12/12 16:00:15 louie 43: * Test release of new UNIX NTP software. This version should conform to the 44: * revised NTP protocol specification. 45: * 46: */ 47: 48: #include <sys/types.h> 49: #include <sys/param.h> 50: #include <sys/ioctl.h> 51: #include <sys/file.h> 52: #include <sys/socket.h> 53: #include <netinet/in.h> 54: #include <net/if.h> 55: #include <errno.h> 56: #include <syslog.h> 57: #include <stdio.h> 58: #include "ntp.h" 59: 60: #define MAX_INTF 10 61: struct intf addrs[MAX_INTF]; 62: int nintf; 63: 64: #ifdef TEST 65: extern int errno; 66: 67: main() { 68: int i, cc, val; 69: char foo[10]; 70: 71: syslog(LOG_ERR, "ifconfig test"); 72: create_sockets(htons(43242)); 73: for (i = 0; i < nintf; i++) { 74: printf("%d: %s fd %d addr %s mask %x ", 75: i, addrs[i].name, addrs[i].fd, 76: inet_ntoa(addrs[i].sin.sin_addr.s_addr), 77: ntohl(addrs[i].mask.sin_addr.s_addr)); 78: cc = sizeof(val); 79: if (getsockopt(addrs[0].fd, SOL_SOCKET, SO_BROADCAST, 80: (char*)&val, &cc)) { 81: perror("getsockopt"); 82: exit(1); 83: } 84: printf("BCAST opt %d", val); 85: cc = sizeof(val); 86: if (getsockopt(addrs[0].fd, SOL_SOCKET, SO_RCVBUF, 87: (char*)&val, &cc)) { 88: perror("getsockopt"); 89: exit(1); 90: } 91: printf("sockbuf size = %d ", val); 92: putchar('\n'); 93: } 94: 95: for (i=0; i < nintf; i++) { 96: fprintf(stderr, "Read fd %d.. ", addrs[i].fd); 97: cc = read(addrs[i].fd, foo, 10); 98: fprintf(stderr, " returns %d ", cc); 99: perror("read errno"); 100: } 101: } 102: #endif 103: 104: #ifndef SIOCGIFCONF 105: /* 106: * If we can't determine the interface configuration, just listen with one 107: * socket at the INADDR_ANY address. 108: */ 109: create_sockets(port) 110: unsigned int port; 111: { 112: addrs[0].sin.sin_family = AF_INET; 113: addrs[0].sin.sin_port = 0; 114: addrs[0].sin.sin_addr.s_addr = INADDR_ANY; 115: addrs[0].sin.sin_mask.s_addr = htonl(~0); 116: addrs[0].name = "wildcard"; 117: 118: if ((addrs[0].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 119: syslog(LOG_ERR, "socket() failed: %m"); 120: #ifdef TEST 121: perror( "socket() failed"); 122: #endif 123: exit(1); 124: /*NOTREACHED*/ 125: } 126: 127: if (fcntl(addrs[i].fd, F_SETFL, FNDELAY) < 0) { 128: syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); 129: #ifdef TEST 130: perror("fcntl(FNDELAY) fails"); 131: #endif 132: exit(1); 133: /*NOTREACHED*/ 134: } 135: addrs[0].sin.sin_family = AF_INET; 136: addrs[0].sin.sin_port = port; 137: addrs[0].if_flags = 0; 138: if (bind(addrs[0].fd, (struct sockaddr *)&addrs[0].sin, 139: sizeof(addrs[0].sin)) < 0) { 140: syslog(LOG_ERR, "bind() fails: %m"); 141: #ifdef TEST 142: perror("bind fails\n"); 143: #endif 144: exit(1); 145: } 146: nintf = 1; 147: return nintf; 148: } 149: #else 150: /* 151: * Grab interface configuration, and create a socket for each interface 152: * address. 153: */ 154: create_sockets(port) 155: unsigned int port; 156: { 157: char buf[1024]; 158: struct ifconf ifc; 159: struct ifreq ifreq, *ifr; 160: int on = 1, off = 0; 161: int n, i, vs; 162: extern char *malloc(); 163: 164: /* 165: * create pseudo-interface with wildcard address 166: */ 167: addrs[nintf].sin.sin_family = AF_INET; 168: addrs[nintf].sin.sin_port = 0; 169: addrs[nintf].sin.sin_addr.s_addr = INADDR_ANY; 170: addrs[nintf].name = "wild"; 171: addrs[nintf].mask.sin_addr.s_addr = htonl(~0); 172: 173: nintf = 1; 174: 175: if ((vs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 176: syslog(LOG_ERR, "vs=socket(AF_INET, SOCK_DGRAM) %m"); 177: #ifdef TEST 178: perror("vs=socket(AF_INET, SOCK_DGRAM)"); 179: #endif 180: exit(1); 181: } 182: ifc.ifc_len = sizeof(buf); 183: ifc.ifc_buf = buf; 184: if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) { 185: syslog(LOG_ERR, "get interface configuration: %m"); 186: #ifdef TEST 187: perror("ioctl(SIOCGIFCONF) fails"); 188: #endif 189: exit(1); 190: } 191: n = ifc.ifc_len/sizeof(struct ifreq); 192: 193: for (ifr = ifc.ifc_req; n > 0; n--, ifr++) { 194: if (ifr->ifr_addr.sa_family != AF_INET) 195: continue; 196: ifreq = *ifr; 197: if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 198: syslog(LOG_ERR, "get interface flags: %m"); 199: #ifdef TEST 200: perror("SIOCGIFFFLAGS fails"); 201: #endif 202: continue; 203: } 204: if ((ifreq.ifr_flags & IFF_UP) == 0) 205: continue; 206: addrs[nintf].if_flags = ifreq.ifr_flags; 207: 208: if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) { 209: syslog(LOG_ERR, "get interface addr: %m"); 210: #ifdef TEST 211: perror("SIOCGIFADDR fails"); 212: #endif 213: continue; 214: } 215: if ((addrs[nintf].name = malloc(strlen(ifreq.ifr_name)+1)) 216: == NULL) { 217: syslog(LOG_ERR, "malloc failed"); 218: exit(1); 219: } 220: strcpy(addrs[nintf].name, ifreq.ifr_name); 221: addrs[nintf].sin = *(struct sockaddr_in *)&ifreq.ifr_addr; 222: 223: #ifdef SIOCGIFBRDADDR 224: if (addrs[nintf].if_flags & IFF_BROADCAST) { 225: if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 226: syslog(LOG_ERR, "SIOCGIFBRDADDR fails"); 227: #ifdef TEST 228: perror("SIOCGIFBRDADDR fails"); 229: #endif 230: exit(1); 231: } 232: #ifndef SUN_3_3 233: addrs[nintf].bcast = 234: *(struct sockaddr_in *)&ifreq.ifr_broadaddr; 235: #else 236: addrs[nintf].bcast = 237: *(struct sockaddr_in *)&ifreq.ifr_addr; 238: #endif 239: } 240: #endif /* SIOCGIFBRDADDR */ 241: #ifdef SIOCGIFNETMASK 242: if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 243: syslog(LOG_ERR, "SIOCGIFNETMASK fails"); 244: #ifdef TEST 245: perror("SIOCGIFNETMASK fails"); 246: #endif 247: exit(1); 248: } 249: addrs[nintf].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; 250: #endif /* SIOCGIFNETMASK */ 251: 252: /* 253: * look for an already existing source interface address. If 254: * the machine has multiple point to point interfaces, then 255: * the local address may appear more than once. 256: */ 257: for (i=0; i < nintf; i++) 258: if (addrs[i].sin.sin_addr.s_addr == 259: addrs[nintf].sin.sin_addr.s_addr) { 260: #ifdef TEST 261: printf("dup interface address %s on %s\n", 262: inet_ntoa(addrs[nintf].sin.sin_addr.s_addr), 263: ifreq.ifr_name); 264: #endif 265: goto next; 266: } 267: nintf++; 268: next:; 269: } 270: close(vs); 271: 272: for (i = 0; i < nintf; i++) { 273: /* create a datagram (UDP) socket */ 274: if ((addrs[i].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 275: syslog(LOG_ERR, "socket() failed: %m"); 276: #ifdef TEST 277: perror("socket(AF_INET, SOCK_DGRAM) fails"); 278: #endif 279: exit(1); 280: /*NOTREACHED*/ 281: } 282: 283: /* set SO_REUSEADDR since we will be binding the same port 284: number on each interface */ 285: if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_REUSEADDR, 286: (char *)&on, sizeof(on))) { 287: #ifdef TEST 288: perror("setsockopt SO_REUSEADDR on"); 289: #endif 290: syslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m"); 291: } 292: 293: /* 294: * set non-blocking I/O on the descriptor 295: */ 296: if (fcntl(addrs[i].fd, F_SETFL, FNDELAY) < 0) { 297: syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); 298: #ifdef TEST 299: perror("fcntl(F_SETFL, FNDELAY) fails"); 300: #endif 301: exit(1); 302: /*NOTREACHED*/ 303: } 304: 305: /* 306: * finally, bind the local address address. 307: */ 308: addrs[i].sin.sin_family = AF_INET; 309: addrs[i].sin.sin_port = port; 310: if (bind(addrs[i].fd, (struct sockaddr *)&addrs[i].sin, 311: sizeof(addrs[i].sin)) < 0) { 312: syslog(LOG_ERR, "bind() fails: %m"); 313: #ifdef TEST 314: perror("bind fails"); 315: #endif 316: exit(1); 317: } 318: 319: /* 320: * Turn off the SO_REUSEADDR socket option. It apparently 321: * causes heartburn on systems with multicast IP installed. 322: * On normal systems it only gets looked at when the address 323: * is being bound anyway.. 324: */ 325: if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_REUSEADDR, 326: (char *)&off, sizeof(off))) { 327: syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); 328: #ifdef TEST 329: perror("setsockopt SO_REUSEADDR off"); 330: #endif 331: } 332: 333: #ifdef SO_BROADCAST 334: /* if this interface can support broadcast, set SO_BROADCAST */ 335: if (addrs[i].if_flags & IFF_BROADCAST) { 336: if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_BROADCAST, 337: (char *)&on, sizeof(on))) { 338: syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); 339: #ifdef TEST 340: perror("setsockopt(SO_BROADCAST) on"); 341: #endif 342: } 343: } 344: #endif /* SO_BROADCAST */ 345: } 346: return nintf; 347: } 348: 349: #endif