EXPERIMENTAL ftp IPV6 Support

This commit is contained in:
Andrew Pamment 2017-04-05 09:04:06 +10:00
parent c3733722e6
commit 34401dbd7e
2 changed files with 117 additions and 33 deletions

View File

@ -199,18 +199,18 @@ void close_tcp_connection(struct ftpclient* client) {
client->data_socket = -1; client->data_socket = -1;
} }
if (strlen(client->data_ip) > 0) { if (strlen(client->data_ip) > 0) {
memset(client->data_ip, 0, 20); memset(client->data_ip, 0, INET6_ADDRSTRLEN);
client->data_port = 0; client->data_port = 0;
} }
} }
int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) { int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
if (strlen(client->data_ip) != 0) { if (strlen(client->data_ip) != 0) {
client->data_socket = socket(AF_INET, SOCK_STREAM, 0); client->data_socket = socket(AF_INET6, SOCK_STREAM, 0);
struct sockaddr_in servaddr; struct sockaddr_in6 servaddr;
servaddr.sin_family = AF_INET; servaddr.sin6_family = AF_INET6;
servaddr.sin_port = htons(client->data_port); servaddr.sin6_port = htons(client->data_port);
if (inet_aton(client->data_ip, &(servaddr.sin_addr)) <= 0) { if (inet_pton(AF_INET6, client->data_ip, &(servaddr.sin6_addr)) <= 0) {
fprintf(stderr, "Error in port command\n"); fprintf(stderr, "Error in port command\n");
return 0; return 0;
} }
@ -220,7 +220,7 @@ int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
} }
} else if (client->data_srv_socket != 0) { } else if (client->data_srv_socket != 0) {
socklen_t sock = sizeof(struct sockaddr); socklen_t sock = sizeof(struct sockaddr);
struct sockaddr_in data_client; struct sockaddr_in6 data_client;
client->data_socket = accept(client->data_srv_socket, (struct sockaddr*) &data_client, &sock); client->data_socket = accept(client->data_srv_socket, (struct sockaddr*) &data_client, &sock);
if (client->data_socket < 0) { if (client->data_socket < 0) {
@ -295,7 +295,7 @@ void handle_STOR(struct ftpserver *cfg, struct ftpclient *client, char *path) {
send_msg(client, "451 STOR Failed.\r\n"); send_msg(client, "451 STOR Failed.\r\n");
} else { } else {
client->data_socket = -1; client->data_socket = -1;
memset(client->data_ip, 0, 20); memset(client->data_ip, 0, INET6_ADDRSTRLEN);
client->data_srv_socket = -1; client->data_srv_socket = -1;
} }
} else { } else {
@ -309,6 +309,52 @@ void handle_STOR(struct ftpserver *cfg, struct ftpclient *client, char *path) {
} }
} }
void handle_EPSV(struct ftpserver *cfg, struct ftpclient *client) {
if (client->data_socket > 0) {
close(client->data_socket);
client->data_socket = -1;
}
if (client->data_srv_socket > 0) {
close(client->data_srv_socket);
}
client->data_srv_socket = socket(AF_INET6, SOCK_STREAM, 0);
if (client->data_srv_socket < 0) {
send_msg(client, "500 EPSV failure.\r\n");
return;
}
struct sockaddr_in6 server;
server.sin6_family = AF_INET6;
server.sin6_addr = in6addr_any;
cfg->last_passive_port++;
if (cfg->last_passive_port == cfg->max_passive_port) {
cfg->last_passive_port = cfg->min_passive_port;
}
int port = cfg->last_passive_port;
server.sin6_port = htons(port);
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(struct sockaddr)) < 0) {
send_msg(client, "500 EPSV failure\r\n");
return;
}
if (listen(client->data_srv_socket, 1) < 0) {
send_msg(client, "500 EPSV failure\r\n");
}
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];
sprintf(buffer, "229 Entering Extended Passive Mode (|||%d|)", port);
send_msg(client, buffer);
}
void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) { void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
char buffer[200]; char buffer[200];
char *ipcpy; char *ipcpy;
@ -322,14 +368,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_INET, SOCK_STREAM, 0); client->data_srv_socket = socket(AF_INET6, 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_in server; struct sockaddr_in6 server;
server.sin_family = AF_INET; server.sin6_family = AF_INET6;
server.sin_addr.s_addr = INADDR_ANY; server.sin6_addr = in6addr_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) {
@ -338,7 +384,7 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
int port = cfg->last_passive_port; int port = cfg->last_passive_port;
server.sin_port = htons(port); server.sin6_port = htons(port);
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(struct sockaddr)) < 0) { if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(struct sockaddr)) < 0) {
send_msg(client, "426 PASV failure\r\n"); send_msg(client, "426 PASV failure\r\n");
@ -349,23 +395,11 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
send_msg(client, "426 PASV failure\r\n"); send_msg(client, "426 PASV failure\r\n");
} }
struct sockaddr_in file_addr; struct sockaddr_in6 file_addr;
socklen_t file_sock_len = sizeof(struct sockaddr); socklen_t file_sock_len = sizeof(struct sockaddr_in6);
getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len); getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len);
ipcpy = strdup(client->hostip);
ipptr = strtok(ipcpy, ".");
strcpy(buffer, "227 Entering Passive Mode ("); strcpy(buffer, "227 Entering Passive Mode (");
while (ipptr != NULL) {
sprintf(buffer, "%s%s,", buffer, ipptr);
ipptr = strtok(NULL, ".");
}
sprintf(buffer, "%s%d,%d)\r\n", buffer, port / 256, port % 256);
send_msg(client, buffer); send_msg(client, buffer);
free(ipcpy); free(ipcpy);
} }
@ -392,7 +426,7 @@ void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
if (pid > 0) { if (pid > 0) {
// nothing // nothing
client->data_socket = -1; client->data_socket = -1;
memset(client->data_ip, 0, 20); memset(client->data_ip, 0, INET6_ADDRSTRLEN);
client->data_srv_socket = -1; client->data_srv_socket = -1;
} else if (pid == 0) { } else if (pid == 0) {
@ -443,7 +477,7 @@ void handle_LIST(struct ftpserver *cfg, struct ftpclient *client) {
if (pid > 0) { if (pid > 0) {
// nothing // nothing
client->data_socket = -1; client->data_socket = -1;
memset(client->data_ip, 0, 20); memset(client->data_ip, 0, INET6_ADDRSTRLEN);
client->data_srv_socket = -1; client->data_srv_socket = -1;
} else if (pid == 0) { } else if (pid == 0) {
dirp = opendir(newpath); dirp = opendir(newpath);
@ -498,11 +532,55 @@ 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, "%d.%d.%d.%d", a, b, c, d); sprintf(client->data_ip, "::ffff:%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");
} }
void handle_EPRT(struct ftpserver *cfg, struct ftpclient *client, char *arg) {
if (client->data_socket > 0) {
close(client->data_socket);
}
int a,b,c,d,e,f;
char delim[2];
char *ptr;
int addrtype;
delim[0] = arg[0];
delim[1] = '\0';
ptr = strtok(arg, delim);
if (ptr != NULL) {
addrtype = atoi(ptr);
if (addrtype == 1) {
//ipv4
ptr = strtok(NULL, delim);
if (ptr != NULL) {
sprintf(client->data_ip, "::ffff:%s", ptr);
ptr = strtok(NULL, delim);
if (ptr != NULL) {
client->data_port = atoi(ptr);
send_msg(client, "200 EPRT command successful.\r\n");
return;
}
}
} else if (addrtype == 2) {
//ipv6
ptr = strtok(NULL, delim);
if (ptr != NULL) {
sprintf(client->data_ip, "%s", ptr);
ptr = strtok(NULL, delim);
if (ptr != NULL) {
client->data_port = atoi(ptr);
send_msg(client, "200 EPRT command successful.\r\n");
return;
}
}
}
}
}
void handle_CWD(struct ftpserver *cfg, struct ftpclient *client, char *dir) { void handle_CWD(struct ftpserver *cfg, struct ftpclient *client, char *dir) {
char *newpath; char *newpath;
char fullpath[PATH_MAX]; char fullpath[PATH_MAX];
@ -689,6 +767,12 @@ int handle_client(struct ftpserver *cfg, struct ftpclient *client, char *buf, in
} else } else
if (strcmp(cmd, "STOR") == 0) { if (strcmp(cmd, "STOR") == 0) {
handle_STOR(cfg, client, argument); handle_STOR(cfg, client, argument);
} else
if (strcmp(cmd, "EPRT") == 0) {
handle_EPRT(cfg, client, argument);
} else
if (strcmp(cmd, "EPSV") == 0) {
handle_EPSV(cfg, client);
} else { } else {
send_msg(client, "500 Command not recognized.\r\n"); send_msg(client, "500 Command not recognized.\r\n");
} }

View File

@ -5,11 +5,11 @@ struct ftpclient {
int fd; int fd;
int data_socket; int data_socket;
char current_path[PATH_MAX]; char current_path[PATH_MAX];
char data_ip[20]; char data_ip[INET6_ADDRSTRLEN];
int data_port; int data_port;
int type; int type;
char ip[20]; char ip[INET6_ADDRSTRLEN];
char hostip[20]; char hostip[INET6_ADDRSTRLEN];
char name[16]; char name[16];
char password[32]; char password[32];
int data_srv_socket; int data_srv_socket;