Skip to content

Instantly share code, notes, and snippets.

@yne
Created December 18, 2015 22:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yne/20d1bdadab88d13b0e0d to your computer and use it in GitHub Desktop.
Save yne/20d1bdadab88d13b0e0d to your computer and use it in GitHub Desktop.
Offer an active FTP interface over a passiv FTP server
#include <stdlib.h>//exit
#include <stdio.h>
#include <pthread.h>
#include <netdb.h> //NI_NUMERICHOST
#include <string.h>//strlen
#include <unistd.h>//read write close fork
#define ss2sa(ss) ((struct sockaddr *)(ss))
#define $(X) if((err=(X))<0)die(__LINE__,err)
#define Write(A,B) write(A,B,strlen(B))
#define Read(A,B) len=read(A,B,sizeof(B));buf[len]=0;
typedef void*(*Threadp)(void *);
struct addrinfo hints={AI_PASSIVE,AF_INET,SOCK_STREAM};
void die(int line,int code){
printf("erreur @%i -> (%i)\n",line,code);
exit(code);
}
void arg2addr(char*buf,char*ip,char*port,int cli){
int ip1,ip2,ip3,ip4,port1,port2;
if(cli)sscanf(buf,"PORT %i,%i,%i,%i,%i,%i",&ip1,&ip2,&ip3,&ip4,&port1,&port2);
else sscanf(buf,"227 Entering Passive Mode (%i,%i,%i,%i,%i,%i)",&ip1,&ip2,&ip3,&ip4,&port1,&port2);
sprintf(ip,"%i.%i.%i.%i",ip1,ip2,ip3,ip4);
sprintf(port,"%i",(port1<<8)+port2);
}
int newSocket(char*ip,char*port,int isbind){
int err,fd;struct addrinfo*res;
$(fd=socket(AF_INET, SOCK_STREAM, 0));
$(getaddrinfo(ip,port,&hints,&res));
if(isbind)bind(fd,res->ai_addr, res->ai_addrlen);
else connect(fd,res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
return fd;
}
void bridge(int*arg){
while(1){
char buf[1500];
int len=read(arg[arg[2]?0:1],buf,sizeof(buf));
if(write(arg[arg[2]?1:0],buf,len)<=0)break;
}
close(arg[0]);
close(arg[1]);
}
void proxy(int client){
char buf[256],_user[48],user[32],host[32],port[6]="21";
pthread_t thread1;
int server,err,len,arg[3];//{cli,srv,sens}
Write(client,"220 Bonjour\r\n");
Read(client,buf);
sscanf(buf,"USER %31[^@]@%31[^:\r]:%5[^\r]",user,host,port);//anonymous@ftp.irit.fr:21
$(server=newSocket(host,port,0));
sprintf(_user,"USER %s\r\n",user);
Read(server,buf);//recois le 220 du serv
Write(server,_user);
while(1){//boucle principale
do{
Read (server,buf);
printf("srv:%s",buf);
if(!Write(client,buf))exit(0);
}while(buf[0]=='1');
do{
Read(client,buf);
if(memcmp("PASV",buf,4))break;
Write(client,"500\r\n");//tu devrais etre actif toi !
}while(1);
if(!memcmp("PORT",buf,4)){//le client veut qu'on vienne le chercher
arg2addr(buf,host,port,1);//printf("client <%s:%s>\n",ip,port);
arg[1]=newSocket(host,port,0);//client
Write(server,"PASV\r\n");
Read (server,buf);
arg2addr(buf,host,port,0);//printf("server <%s:%s>\n",ip,port);
arg[0]=newSocket(host,port,0);//serv
Write(client,"200 le serv est OP\r\n");
Read (client,buf);//lit la commande
if(!memcmp("LIST",buf,4)
||!memcmp("GET" ,buf,3))arg[2]=1;//le thread est en mode cli<<srv
if(!memcmp("STOR",buf,4))arg[2]=0;//le thread est en mode cli>>srv
pthread_create( &thread1, NULL,(Threadp) bridge, (void*) arg);
}
printf("cli:%s",buf);
if(!Write(server,buf))exit(0);
}
}
int main(int argc,char* argv[]){
int err,client,prox=newSocket("127.0.0.1","0",1);
struct sockaddr_storage info,from;
unsigned socklen=sizeof(struct sockaddr_storage);
char ip[64],port[6];
$(getsockname(prox,ss2sa(&info),&socklen));
$(getnameinfo(ss2sa(&info),sizeof(info),ip,sizeof(ip),port,sizeof(port),3));
printf("listen on %s:%s\n", ip,port);
$(listen(prox, 1));//attente de connection
while(1){
$(client=accept(prox,ss2sa(&from), &socklen));
if(!fork()){
close(prox);
proxy(client);
}else close(client);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment