Whamcloud - gitweb
e5bb46b0b5e37787f1afd0cffded78e1bf7f8367
[fs/lustre-release.git] / lnet / utils / acceptor.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  */
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/tcp.h>
8 #include <netdb.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <unistd.h>
14 #include <syslog.h>
15 #include <errno.h>
16 #ifdef HAVE_LIBWRAP
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <tcpd.h>
20 #endif
21
22 #include <libcfs/portals_utils.h>
23 #include <portals/api-support.h>
24 #include <portals/lib-types.h>
25 #include <portals/socknal.h>
26
27 /* should get this from autoconf somehow */
28 #ifndef PIDFILE_DIR
29 #define PIDFILE_DIR "/var/run"
30 #endif 
31
32 #define PROGNAME "acceptor"
33
34 #ifdef HAVE_LIBWRAP
35 /* needed because libwrap declares these as externs */
36 int     allow_severity = LOG_INFO;
37 int     deny_severity = LOG_WARNING;
38 #endif
39
40 void create_pidfile(char *name, int port)
41 {
42         char pidfile[1024];
43         FILE *fp;
44
45         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
46                  PIDFILE_DIR, name, port);
47         
48         if ((fp = fopen(pidfile, "w"))) {
49                 fprintf(fp, "%d\n", getpid());
50                 fclose(fp);
51         } else {
52                 syslog(LOG_ERR, "%s: %s\n", pidfile, 
53                        strerror(errno));
54         }
55 }
56
57 int pidfile_exists(char *name, int port)
58 {
59         char pidfile[1024];
60
61         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
62                  PIDFILE_DIR, name, port);
63         
64         if (!access(pidfile, F_OK)) {
65                 fprintf(stderr, "%s: exists, acceptor already running.\n", 
66                         pidfile);
67                 return (1);
68         } 
69         return (0);
70 }
71
72 void
73 show_connection (int fd, __u32 net_ip)
74 {
75         struct hostent *h = gethostbyaddr ((char *)&net_ip, sizeof net_ip, AF_INET);
76         __u32 host_ip = ntohl (net_ip);
77         int  len;
78         char host[1024];
79         
80         if (h == NULL)
81                 snprintf (host, sizeof(host), "%d.%d.%d.%d", (host_ip >> 24) & 0xff,
82                                     (host_ip >> 16) & 0xff, (host_ip >> 8) & 0xff, host_ip & 0xff);
83         else
84                 snprintf (host, sizeof(host), "%s", h->h_name);
85                 
86         syslog (LOG_INFO, "Accepted host: %s\n", host);
87 }
88
89 void
90 usage (char *myname)
91 {
92         fprintf (stderr, 
93                  "Usage: %s [-N nal_id] [-p] [-l] port\n\n"
94                  " -l\tKeep stdin/stdout open\n"
95                  " -p\tAllow connections from non-privileged ports\n",
96                  myname);
97         exit (1);
98 }
99
100 int main(int argc, char **argv)
101 {
102         int o, fd, rc, port, pfd;
103         struct sockaddr_in srvaddr;
104         int c;
105         int noclose = 0;
106         int nal = SOCKNAL;
107         int rport;
108         int require_privports = 1;
109         
110         while ((c = getopt (argc, argv, "N:lp")) != -1) {
111                 switch (c) {
112                 case 'N':
113                         if (sscanf(optarg, "%d", &nal) != 1 ||
114                             nal < 0 || nal > NAL_MAX_NR)
115                                 usage(argv[0]);
116                         break;
117                 case 'l':
118                         noclose = 1;
119                         break;
120                 case 'p':
121                         require_privports = 0;
122                         break;
123                 default:
124                         usage (argv[0]);
125                         break;
126                 }
127         }
128
129         if (optind >= argc)
130                 usage (argv[0]);
131
132         port = atol(argv[optind++]);
133
134         if (pidfile_exists(PROGNAME, port))
135                 exit(1);
136
137         memset(&srvaddr, 0, sizeof(srvaddr));
138         srvaddr.sin_family = AF_INET;
139         srvaddr.sin_port = htons(port);
140         srvaddr.sin_addr.s_addr = INADDR_ANY;
141
142         fd = socket(PF_INET, SOCK_STREAM, 0);
143         if (fd < 0) {
144                 perror("opening socket");
145                 exit(1);
146         }
147
148         o = 1;
149         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
150                 perror("Cannot set REUSEADDR socket opt");
151                 exit(1);
152         }
153
154         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
155         if ( rc == -1 ) {
156                 perror("bind: ");
157                 exit(1);
158         }
159
160         if (listen(fd, 127)) {
161                 perror("listen: ");
162                 exit(1);
163         }
164         fprintf(stderr, "listening on port %d\n", port);
165
166         pfd = open("/dev/portals", O_RDWR);
167         if ( pfd < 0 ) {
168                 perror("opening portals device");
169                 exit(1);
170         }
171
172         rc = daemon(0, noclose);
173         if (rc < 0) {
174                 perror("daemon(): ");
175                 exit(1);
176         }
177
178         openlog(PROGNAME, LOG_PID, LOG_DAEMON);
179         syslog(LOG_INFO, "started, listening on port %d\n", port);
180         create_pidfile(PROGNAME, port);
181
182         while (1) {
183                 struct sockaddr_in clntaddr;
184                 int len = sizeof(clntaddr);
185                 int cfd;
186                 struct portal_ioctl_data data;
187                 struct portals_cfg pcfg;
188 #ifdef HAVE_LIBWRAP
189                 struct request_info request;
190 #endif
191                 char addrstr[INET_ADDRSTRLEN];
192                
193                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
194                 if ( cfd < 0 ) {
195                         perror("accept");
196                         exit(0);
197                         continue;
198                 }
199
200 #ifdef HAVE_LIBWRAP
201                 /* libwrap access control */
202                 request_init(&request, RQ_DAEMON, "lustre", RQ_FILE, cfd, 0);
203                 sock_host(&request);
204                 if (!hosts_access(&request)) {
205                         inet_ntop(AF_INET, &clntaddr.sin_addr,
206                                   addrstr, INET_ADDRSTRLEN);
207                         syslog(LOG_WARNING, "Unauthorized access from %s:%hd\n",
208                                addrstr, ntohs(clntaddr.sin_port));
209                         close (cfd);
210                         continue;
211                 }
212 #endif
213
214                 if (require_privports && ntohs(clntaddr.sin_port) >= IPPORT_RESERVED) {
215                         inet_ntop(AF_INET, &clntaddr.sin_addr,
216                                   addrstr, INET_ADDRSTRLEN);
217                         syslog(LOG_ERR, "Closing non-privileged connection from %s:%d\n",
218                                addrstr, ntohs(clntaddr.sin_port));
219                         rc = close(cfd);
220                         if (rc)
221                                 perror ("close un-privileged client failed");
222                         continue;
223                 }
224
225                 show_connection (cfd, clntaddr.sin_addr.s_addr);
226
227                 PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
228                 pcfg.pcfg_nal = nal;
229                 pcfg.pcfg_fd = cfd;
230                 pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
231                 
232                 PORTAL_IOC_INIT(data);
233                 data.ioc_pbuf1 = (char*)&pcfg;
234                 data.ioc_plen1 = sizeof(pcfg);
235                 
236                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
237                         perror("ioctl failed");
238                 } else {
239                         printf("client registered\n");
240                 }
241                 rc = close(cfd);
242                 if (rc)
243                         perror ("close failed");
244         }
245
246         closelog();
247         exit(0);
248
249 }