Update magiftpd to use new dual stack
This commit is contained in:
parent
36fb2c95ab
commit
26ddf9415f
@ -146,6 +146,12 @@ static int handler(void* user, const char* section, const char* name, const char
|
|||||||
cfg->min_passive_port = atoi(value);
|
cfg->min_passive_port = atoi(value);
|
||||||
} else if (strcasecmp(name, "max passive port") == 0) {
|
} else if (strcasecmp(name, "max passive port") == 0) {
|
||||||
cfg->max_passive_port = atoi(value);
|
cfg->max_passive_port = atoi(value);
|
||||||
|
} else if (strcasecmp(name, "enable ipv6") == 0) {
|
||||||
|
if (strcasecmp(value, "true") == 0) {
|
||||||
|
cfg->ipv6 = 1;
|
||||||
|
} else {
|
||||||
|
cfg->ipv6 = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -213,6 +219,7 @@ void close_tcp_connection(struct ftpclient* client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
|
int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
|
if (client->ipver == 6) {
|
||||||
if (strlen(client->data_ip) != 0) {
|
if (strlen(client->data_ip) != 0) {
|
||||||
client->data_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
client->data_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
struct sockaddr_in6 servaddr;
|
struct sockaddr_in6 servaddr;
|
||||||
@ -237,6 +244,32 @@ int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (strlen(client->data_ip) != 0) {
|
||||||
|
client->data_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
struct sockaddr_in servaddr;
|
||||||
|
servaddr.sin_family = AF_INET;
|
||||||
|
servaddr.sin_port = htons(client->data_port);
|
||||||
|
if (inet_pton(AF_INET, client->data_ip, &(servaddr.sin_addr)) <= 0) {
|
||||||
|
fprintf(stderr, "Error in port command\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (connect(client->data_socket, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
|
||||||
|
perror("Connect");
|
||||||
|
fprintf(stderr, "Error connecting to client\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (client->data_srv_socket != 0) {
|
||||||
|
socklen_t sock = sizeof(struct sockaddr);
|
||||||
|
struct sockaddr_in data_client;
|
||||||
|
client->data_socket = accept(client->data_srv_socket, (struct sockaddr*) &data_client, &sock);
|
||||||
|
|
||||||
|
if (client->data_socket < 0) {
|
||||||
|
fprintf(stderr, "Accept Error\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,6 +352,10 @@ void handle_STOR(struct ftpserver *cfg, struct ftpclient *client, char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handle_EPSV(struct ftpserver *cfg, struct ftpclient *client) {
|
void handle_EPSV(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
|
struct sockaddr_in6 server;
|
||||||
|
struct sockaddr_in server4;
|
||||||
|
void *server_p;
|
||||||
|
|
||||||
if (client->data_socket > 0) {
|
if (client->data_socket > 0) {
|
||||||
close(client->data_socket);
|
close(client->data_socket);
|
||||||
client->data_socket = -1;
|
client->data_socket = -1;
|
||||||
@ -328,14 +365,25 @@ void handle_EPSV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
close(client->data_srv_socket);
|
close(client->data_srv_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client->ipver == 6) {
|
||||||
client->data_srv_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
client->data_srv_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
} else {
|
||||||
|
client->data_srv_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
}
|
||||||
if (client->data_srv_socket < 0) {
|
if (client->data_srv_socket < 0) {
|
||||||
send_msg(client, "500 EPSV failure.\r\n");
|
send_msg(client, "500 EPSV failure.\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct sockaddr_in6 server;
|
|
||||||
|
if (client->ipver == 6) {
|
||||||
server.sin6_family = AF_INET6;
|
server.sin6_family = AF_INET6;
|
||||||
server.sin6_addr = in6addr_any;
|
server.sin6_addr = in6addr_any;
|
||||||
|
server_p = &server;
|
||||||
|
} else {
|
||||||
|
server4.sin_family = AF_INET;
|
||||||
|
server4.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
server_p = &server;
|
||||||
|
}
|
||||||
|
|
||||||
cfg->last_passive_port++;
|
cfg->last_passive_port++;
|
||||||
if (cfg->last_passive_port == cfg->max_passive_port) {
|
if (cfg->last_passive_port == cfg->max_passive_port) {
|
||||||
@ -344,21 +392,27 @@ void handle_EPSV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
|
|
||||||
int port = cfg->last_passive_port;
|
int port = cfg->last_passive_port;
|
||||||
|
|
||||||
|
if (client->ipver == 6) {
|
||||||
server.sin6_port = htons(port);
|
server.sin6_port = htons(port);
|
||||||
|
|
||||||
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(server)) < 0) {
|
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(server)) < 0) {
|
||||||
send_msg(client, "500 EPSV failure\r\n");
|
send_msg(client, "500 EPSV failure\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
server4.sin_port = htons(port);
|
||||||
|
if (bind(client->data_srv_socket, (struct sockaddr*) &server4, sizeof(server4)) < 0) {
|
||||||
|
send_msg(client, "500 EPSV failure\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (listen(client->data_srv_socket, 1) < 0) {
|
if (listen(client->data_srv_socket, 1) < 0) {
|
||||||
send_msg(client, "500 EPSV failure\r\n");
|
send_msg(client, "500 EPSV failure\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in6 file_addr;
|
|
||||||
socklen_t file_sock_len = sizeof(struct sockaddr);
|
|
||||||
getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len);
|
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
sprintf(buffer, "229 Entering Extended Passive Mode (|||%d|)\r\n", port);
|
sprintf(buffer, "229 Entering Extended Passive Mode (|||%d|)\r\n", port);
|
||||||
|
|
||||||
@ -378,14 +432,14 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
close(client->data_srv_socket);
|
close(client->data_srv_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
client->data_srv_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
client->data_srv_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (client->data_srv_socket < 0) {
|
if (client->data_srv_socket < 0) {
|
||||||
send_msg(client, "426 PASV failure.\r\n");
|
send_msg(client, "426 PASV failure.\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct sockaddr_in6 server;
|
struct sockaddr_in server;
|
||||||
server.sin6_family = AF_INET6;
|
server.sin_family = AF_INET;
|
||||||
server.sin6_addr = in6addr_any;
|
server.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
cfg->last_passive_port++;
|
cfg->last_passive_port++;
|
||||||
if (cfg->last_passive_port == cfg->max_passive_port) {
|
if (cfg->last_passive_port == cfg->max_passive_port) {
|
||||||
@ -394,7 +448,7 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
|
|
||||||
int port = cfg->last_passive_port;
|
int port = cfg->last_passive_port;
|
||||||
|
|
||||||
server.sin6_port = htons(port);
|
server.sin_port = htons(port);
|
||||||
|
|
||||||
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(server)) < 0) {
|
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(server)) < 0) {
|
||||||
send_msg(client, "426 PASV failure\r\n");
|
send_msg(client, "426 PASV failure\r\n");
|
||||||
@ -406,12 +460,12 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in6 file_addr;
|
struct sockaddr_in file_addr;
|
||||||
socklen_t file_sock_len = sizeof(struct sockaddr_in6);
|
socklen_t file_sock_len = sizeof(struct sockaddr_in);
|
||||||
getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len);
|
getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len);
|
||||||
|
|
||||||
fprintf(stderr, "%s\n", &client->hostip[7]);
|
fprintf(stderr, "%s\n", client->hostip);
|
||||||
ipcpy = strdup(&client->hostip[7]);
|
ipcpy = strdup(client->hostip);
|
||||||
|
|
||||||
ipptr = strtok(ipcpy, ".");
|
ipptr = strtok(ipcpy, ".");
|
||||||
|
|
||||||
@ -556,7 +610,7 @@ void handle_PORT(struct ftpserver *cfg, struct ftpclient *client, char *arg) {
|
|||||||
int a,b,c,d,e,f;
|
int a,b,c,d,e,f;
|
||||||
|
|
||||||
sscanf(arg, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f);
|
sscanf(arg, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f);
|
||||||
sprintf(client->data_ip, "::ffff:%d.%d.%d.%d", a, b, c, d);
|
sprintf(client->data_ip, "%d.%d.%d.%d", a, b, c, d);
|
||||||
client->data_port = e * 256 + f;
|
client->data_port = e * 256 + f;
|
||||||
send_msg(client, "200 PORT command successful.\r\n");
|
send_msg(client, "200 PORT command successful.\r\n");
|
||||||
}
|
}
|
||||||
@ -580,7 +634,7 @@ void handle_EPRT(struct ftpserver *cfg, struct ftpclient *client, char *arg) {
|
|||||||
//ipv4
|
//ipv4
|
||||||
ptr = strtok(NULL, delim);
|
ptr = strtok(NULL, delim);
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
sprintf(client->data_ip, "::ffff:%s", ptr);
|
sprintf(client->data_ip, "%s", ptr);
|
||||||
ptr = strtok(NULL, delim);
|
ptr = strtok(NULL, delim);
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
client->data_port = atoi(ptr);
|
client->data_port = atoi(ptr);
|
||||||
@ -805,8 +859,9 @@ int handle_client(struct ftpserver *cfg, struct ftpclient *client, char *buf, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init(struct ftpserver *cfg) {
|
void init(struct ftpserver *cfg) {
|
||||||
int server_socket;
|
int ipv6_socket, ipv4_socket;
|
||||||
struct sockaddr_in6 server, client, host_addr;
|
struct sockaddr_in6 server, client, host_addr;
|
||||||
|
struct sockaddr_in server4, client4, host_addr4;
|
||||||
fd_set master, read_fds;
|
fd_set master, read_fds;
|
||||||
int fdmax = 0;
|
int fdmax = 0;
|
||||||
socklen_t c;
|
socklen_t c;
|
||||||
@ -814,28 +869,70 @@ void init(struct ftpserver *cfg) {
|
|||||||
char buf[1024];
|
char buf[1024];
|
||||||
int new_fd;
|
int new_fd;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
server_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
int on = 1;
|
||||||
if (server_socket == -1) {
|
|
||||||
|
FD_ZERO(&master);
|
||||||
|
|
||||||
|
if (cfg->ipv6) {
|
||||||
|
ipv6_socket = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
if (ipv6_socket == -1) {
|
||||||
fprintf(stderr, "Couldn't create socket..\n");
|
fprintf(stderr, "Couldn't create socket..\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
if (setsockopt(ipv6_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
|
||||||
|
fprintf(stderr, "setsockopt(SO_REUSEADDR) failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (setsockopt(ipv6_socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)) < 0) {
|
||||||
|
fprintf(stderr, "setsockopt(IPV6_V6ONLY) failed");
|
||||||
|
}
|
||||||
|
|
||||||
server.sin6_family = AF_INET6;
|
server.sin6_family = AF_INET6;
|
||||||
server.sin6_addr = in6addr_any;
|
server.sin6_addr = in6addr_any;
|
||||||
server.sin6_port = htons(cfg->port);
|
server.sin6_port = htons(cfg->port);
|
||||||
|
|
||||||
if (bind(server_socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
|
if (bind(ipv6_socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
|
||||||
perror("Bind Failed, Error\n");
|
perror("Bind Failed, Error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
listen(server_socket, 3);
|
listen(ipv6_socket, 3);
|
||||||
|
FD_SET(ipv6_socket, &master);
|
||||||
|
}
|
||||||
|
|
||||||
FD_ZERO(&master);
|
ipv4_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
FD_SET(server_socket, &master);
|
|
||||||
fdmax = server_socket;
|
|
||||||
|
|
||||||
c = sizeof(struct sockaddr_in6);
|
if (ipv4_socket == -1) {
|
||||||
|
fprintf(stderr, "Couldn't create socket..\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (setsockopt(ipv4_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
|
||||||
|
fprintf(stderr, "setsockopt(SO_REUSEADDR) failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
server4.sin_family = AF_INET;
|
||||||
|
server4.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
server4.sin_port = htons(cfg->port);
|
||||||
|
|
||||||
|
if (bind(ipv4_socket, (struct sockaddr *)&server4, sizeof(server4)) < 0) {
|
||||||
|
perror("Bind Failed, Error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(ipv4_socket, 3);
|
||||||
|
FD_SET(ipv4_socket, &master);
|
||||||
|
|
||||||
|
if (cfg->ipv6) {
|
||||||
|
if (ipv4_socket > ipv6_socket) {
|
||||||
|
fdmax = ipv4_socket;
|
||||||
|
} else {
|
||||||
|
fdmax = ipv6_socket;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fdmax = ipv4_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c = sizeof(struct sockaddr_in6);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
read_fds = master;
|
read_fds = master;
|
||||||
@ -849,8 +946,9 @@ void init(struct ftpserver *cfg) {
|
|||||||
|
|
||||||
for(i = 0; i <= fdmax; i++) {
|
for(i = 0; i <= fdmax; i++) {
|
||||||
if (FD_ISSET(i, &read_fds)) {
|
if (FD_ISSET(i, &read_fds)) {
|
||||||
if (i == server_socket) {
|
if (cfg->ipv6 && i == ipv6_socket) {
|
||||||
new_fd = accept(server_socket, (struct sockaddr *)&client, (socklen_t *)&c);
|
c = sizeof(struct sockaddr_in6);
|
||||||
|
new_fd = accept(ipv6_socket, (struct sockaddr *)&client, (socklen_t *)&c);
|
||||||
if (new_fd == -1) {
|
if (new_fd == -1) {
|
||||||
perror("accept");
|
perror("accept");
|
||||||
} else {
|
} else {
|
||||||
@ -890,7 +988,59 @@ void init(struct ftpserver *cfg) {
|
|||||||
clients[client_count]->seclevel = 0;
|
clients[client_count]->seclevel = 0;
|
||||||
memset(clients[client_count]->name, 0, 16);
|
memset(clients[client_count]->name, 0, 16);
|
||||||
memset(clients[client_count]->password, 0, 32);
|
memset(clients[client_count]->password, 0, 32);
|
||||||
|
clients[client_count]->ipver = 6;
|
||||||
|
client_count++;
|
||||||
|
|
||||||
|
FD_SET(new_fd, &master);
|
||||||
|
if (new_fd > fdmax) {
|
||||||
|
fdmax = new_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_msg(clients[client_count - 1], "220 magiftpd Ready\r\n");
|
||||||
|
}
|
||||||
|
} else if (i == ipv4_socket) {
|
||||||
|
c = sizeof(struct sockaddr_in);
|
||||||
|
new_fd = accept(ipv4_socket, (struct sockaddr *)&client, (socklen_t *)&c);
|
||||||
|
if (new_fd == -1) {
|
||||||
|
perror("accept");
|
||||||
|
} else {
|
||||||
|
if (client_count == 0) {
|
||||||
|
clients = (struct ftpclient **)malloc(sizeof(struct ftpclient *));
|
||||||
|
} else {
|
||||||
|
clients = (struct ftpclient **)realloc(clients, sizeof(struct ftpclient *) * (client_count + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clients) {
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
clients[client_count] = (struct ftpclient *)malloc(sizeof(struct ftpclient));
|
||||||
|
|
||||||
|
memset(clients[client_count], 0, sizeof(struct ftpclient));
|
||||||
|
|
||||||
|
if (!clients[client_count]) {
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getsockname(new_fd, (struct sockaddr*) &host_addr4, &c);
|
||||||
|
inet_ntop(AF_INET, &(host_addr4.sin_addr), clients[client_count]->hostip, INET_ADDRSTRLEN);
|
||||||
|
|
||||||
|
getpeername(new_fd, (struct sockaddr *)&client4, &c);
|
||||||
|
inet_ntop(AF_INET, &(client4.sin_addr), clients[client_count]->ip, INET_ADDRSTRLEN);
|
||||||
|
|
||||||
|
clients[client_count]->fd = new_fd;
|
||||||
|
strcpy(clients[client_count]->current_path, "/");
|
||||||
|
clients[client_count]->data_socket = -1;
|
||||||
|
clients[client_count]->data_srv_socket = -1;
|
||||||
|
clients[client_count]->type = 1;
|
||||||
|
clients[client_count]->status = 0;
|
||||||
|
clients[client_count]->data_port = 0;
|
||||||
|
clients[client_count]->seclevel = 0;
|
||||||
|
memset(clients[client_count]->name, 0, 16);
|
||||||
|
memset(clients[client_count]->password, 0, 32);
|
||||||
|
clients[client_count]->ipver = 4;
|
||||||
client_count++;
|
client_count++;
|
||||||
|
|
||||||
FD_SET(new_fd, &master);
|
FD_SET(new_fd, &master);
|
||||||
@ -968,6 +1118,7 @@ int main(int argc, char **argv) {
|
|||||||
ftpsrv.fileroot = NULL;
|
ftpsrv.fileroot = NULL;
|
||||||
ftpsrv.min_passive_port = 60000;
|
ftpsrv.min_passive_port = 60000;
|
||||||
ftpsrv.max_passive_port = 65000;
|
ftpsrv.max_passive_port = 65000;
|
||||||
|
ftpsrv.ipv6 = 0;
|
||||||
|
|
||||||
sa.sa_handler = sigchld_handler; // reap all dead processes
|
sa.sa_handler = sigchld_handler; // reap all dead processes
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
@ -15,6 +15,7 @@ struct ftpclient {
|
|||||||
int data_srv_socket;
|
int data_srv_socket;
|
||||||
int status;
|
int status;
|
||||||
int seclevel;
|
int seclevel;
|
||||||
|
int ipver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ftpserver {
|
struct ftpserver {
|
||||||
@ -26,6 +27,7 @@ struct ftpserver {
|
|||||||
int min_passive_port;
|
int min_passive_port;
|
||||||
int max_passive_port;
|
int max_passive_port;
|
||||||
int last_passive_port;
|
int last_passive_port;
|
||||||
|
int ipv6;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,3 +12,4 @@ Upload Folder = incoming
|
|||||||
Upload Sec Level = 10
|
Upload Sec Level = 10
|
||||||
Min Passive Port = 60000
|
Min Passive Port = 60000
|
||||||
Max Passive Port = 65000
|
Max Passive Port = 65000
|
||||||
|
Enable IPv6 = true
|
||||||
|
Reference in New Issue
Block a user