Logo Search packages:      
Sourcecode: dctc version File versions  Download package

hublist.c

/* DCTC - a Direct Connect text clone for Linux
 * Copyright (C) 2001 Eric Prevoteau
 *
 * hublist.c: Copyright (C) Eric Prevoteau <www@a2pb.gotdns.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/*
$Id: hublist.c,v 1.9 2003/12/28 08:12:38 uid68112 Exp $
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <signal.h>
#include <glib.h>

#include "format_xml_hublist.h"

static char six2pr[64] = {
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z',
    '0','1','2','3','4','5','6','7','8','9','+','/'
};

/*********************************************************************************************/
/* simple function to encode the login:passwd string for proxy requiring an authentification */
/*********************************************************************************************/
int uu_auth(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
{
#define ENC(c) six2pr[c]

   register char *outptr = bufcoded;
   unsigned int i;
   for (i=0; i<nbytes; i += 3) {
      *(outptr++) = ENC(*bufin >> 2);           /* c1 */
      *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/
      *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/
      *(outptr++) = ENC(bufin[2] & 077);        /* c4 */

      bufin += 3;
   }

   if(i == nbytes+1) {
      /* There were only 2 bytes in that last group */
      outptr[-1] = '=';
   } else if(i == nbytes+2) {
      /* There was only 1 byte in that last group */
      outptr[-1] = '=';
      outptr[-2] = '=';
   }
   *outptr = '\0';
   return(outptr - bufcoded);
}

/* --------------------------------------------------------------------------------------------- */

typedef struct
{
      const char *hostname;
      int hostport;
      const char *query;
      const char *proxyquery;
} HUBSOURCE;

#define NB_HUB_SOURCE 1
static HUBSOURCE hubsource[NB_HUB_SOURCE]= {
                  {     /* source 1: neo-modus hublist */
                        "www.neo-modus.com", 80,
                        "GET /PublicHubList.config HTTP/1.1\n"                            \
                              "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\n"    \
                              "Host: www.neo-modus.com\n"                                 \
                              "Cache-Control: no-cache\n"                                 \
                              "Connection: close\n"                                       \
                              "\n",
                        "GET http://www.neo-modus.com/PublicHubList.config HTTP/1.1\n"    \
                              "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\n"    \
                              "Host: www.neo-modus.com\n"                                 \
                              "Cache-Control: no-cache\n"                                 \
                              "Connection: close\n"                                       \
                              "\n"
                  },
            };
      
FILE *output=NULL;            /* file where result will be sent */

static void process_hub_source(HUBSOURCE *hs, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port);

#ifdef HAVE_BZIP2
static void process_bz2_hub_source(HUBSOURCE *hs, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port);
#endif

static void process_env_sources(const char *envvar, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port);

#define TAILLE 4096

#define DIRECT 1
#define SOCKS 2
#define PROXY 3

/****************************************************************************************/
/* perform the socket connection. Connection is based on value of connect_type.         */
/* If = DIRECT then direct connect is used, if = SOCKS then socks is used, if = DIRECT  */
/* then web proxy is used. And yes I know passing flags is ugly!                        */
/****************************************************************************************/
static int do_connect(int desc,struct sockaddr_in nom,const char *socks_ip,const char *socks_port, const char *socks_name, const int connect_type)
{
      int ret=-1;
      GByteArray *cmd=NULL;
      struct sockaddr_in socks_cnx;
      struct hostent *socks_host;
      unsigned char val[9];

      
      switch(connect_type)
      {
            case DIRECT:
            case PROXY:
                                    alarm(10);
                                    ret=connect(desc,(void*)&nom,sizeof(nom));
                                    alarm(0);
                                    break;

            case SOCKS:
                                    if((socks_host=gethostbyname(socks_ip))==NULL)
                                          goto eofunc;
                                    memcpy(&socks_cnx.sin_addr,socks_host->h_addr,socks_host->h_length);
                                    socks_cnx.sin_family=AF_INET;
                                    socks_cnx.sin_port=htons(strtoul(socks_port,NULL,10));

                                    alarm(10);
                                    ret=connect(desc,(void*)&socks_cnx,sizeof(socks_cnx));
                                    alarm(0);
                                    if(ret==-1)
                                    {
                                          perror("socks connect");
                                          goto eofunc;
                                    }

                                    cmd=g_byte_array_new();
                                    val[0]=4;         /* socks version 4 */
                                    val[1]=1;         /* CONNECT */
                                    val[2]=ntohs(nom.sin_port)>>8;
                                    val[3]=ntohs(nom.sin_port)&255;
                                    val[4]=ntohl(nom.sin_addr.s_addr)>>24;
                                    val[5]=ntohl(nom.sin_addr.s_addr)>>16;
                                    val[6]=ntohl(nom.sin_addr.s_addr)>>8;
                                    val[7]=ntohl(nom.sin_addr.s_addr);
                                    cmd=g_byte_array_append(cmd,val,8);
                                    if(socks_name!=NULL)
                                    {
                                          cmd=g_byte_array_append(cmd,socks_name,strlen(socks_name));
                                    }
                                    val[0]='\0';
                                    cmd=g_byte_array_append(cmd,val,1);
                        
                                    if(send(desc,cmd->data,cmd->len,MSG_NOSIGNAL|MSG_DONTWAIT)!=cmd->len)
                                    {
                                          perror("socks send CONNECT");
                                          ret=-1;
                                          goto eofunc;
                                    }
                        
                                    if(recv(desc,val,8,MSG_WAITALL|MSG_NOSIGNAL)!=8)
                                    {
                                          perror("socks receive CONNECT result");
                                          ret=-1;
                                          goto eofunc;
                                    }

                                    if(val[0]!=0)           /*  reply code version 0 ? */
                                    {
                                          fprintf(stderr,"socks CONNECT result: unknown reply code version (%d)",(int)(val[0]));
                                          ret=-1;
                                          goto eofunc;
                                    }
                        
                                    if(val[1]!=90)
                                    {
                                          fprintf(stderr,"socks CONNECT result: access denied or failed (%d)",(int)(val[1]));
                                          ret=-1;
                                          goto eofunc;
                                    }
                                    ret=0;
#if 0
                                    printf("SOCKS connected\n");
#endif
                                    eofunc:
                                    if(cmd!=NULL)
                                          g_byte_array_free(cmd,TRUE);
                                    break;
      
            default:
                              break;
      }

      return ret;
}

static void catch_sig(int sig)
{
      switch(sig)
      {
            case SIGALRM:
                                    break;
      }
}

/************************************/
/* we don't want to receive SIGPIPE */
/************************************/
static void set_sig(void)
{
      struct sigaction act;
      sigset_t set;

      sigemptyset(&set);
      sigaddset(&set,SIGCHLD);            /* we want to discard potential children */
      act.sa_handler=SIG_IGN;
      act.sa_mask=set;
      act.sa_flags=SA_RESTART;

      sigaction(SIGCHLD,&act,NULL);
      sigprocmask(SIG_UNBLOCK,&set,NULL);

      /* and catch some other sig */
      act.sa_handler=catch_sig;
      act.sa_mask=set;
      act.sa_flags=SA_RESTART;      
      sigaction(SIGALRM,&act,NULL);
      sigprocmask(SIG_UNBLOCK,&set,NULL); /* supprime les signaux */
}

int main(int argc,char **argv)
{
      int i;
      char *socks_ip=NULL;
      char *socks_port=NULL;
      char *user_id=NULL;
      char *proxy_host=NULL;
      char *proxy_port=NULL;
      int connect_type=DIRECT;
      char *envvar=NULL;

      set_sig();

      if(argc!=1)
      {
            if((argc!=4)&&(argc!=5))
            {
                  printf("Usage: %s --socks SocksProxyAddress SocksProxyPort [userID]\n",argv[0]);
                  printf("          --proxy ProxyHost ProxyPort [proxylogin:proxypasswd]\n");
                  exit(0);
            }

            if(strstr(argv[1], "socks") != NULL) {
                  socks_ip=argv[2];
                  socks_port=argv[3];
                  if(argc == 5)
                        user_id=argv[4];
                  connect_type=SOCKS;
#if 0
                  printf("Using socks: '%s' port: '%s' (id: '%s')\n",socks_ip,socks_port, user_id!=NULL?user_id:"");
#endif
            }           
            
            if(strstr(argv[1], "proxy") != NULL) {
                  proxy_host=argv[2];
                  proxy_port=argv[3];
                  connect_type=PROXY;
                  if(argc == 5)
                  {
                        static char encoded_pass[512];
                        if(strlen(argv[4])>256)
                        {
                              uu_auth(argv[4],strlen(argv[4]),encoded_pass);
                        }
                        user_id=encoded_pass;
                  }
#if 1
                  printf("Using proxy: '%s' port: '%s' (id: '%s' encoded into '%s')\n",proxy_host,proxy_port,argc!=5?"":argv[4],user_id!=NULL?user_id:"");
#endif
            }
      }

      output=stdout;

      envvar=getenv("HUBLIST");
      if(envvar==NULL)
      {
            for(i=0;i<NB_HUB_SOURCE;i++)
            {
                  process_hub_source(&hubsource[i], connect_type, socks_ip, socks_port, user_id, proxy_host, proxy_port);
            }
      }
      else
      {
            process_env_sources(envvar,connect_type, socks_ip, socks_port, user_id, proxy_host, proxy_port);
      }
      exit(0);
}

/**************************************************************/
/* split the given env var along "\t" and process each source */
/**************************************************************/
static void process_env_sources(const char *envvar, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port)
{
      gchar **srcs;
      int i;
      GString *hostnm;
      GString *qry;
      GString *pxyqry;

      srcs=g_strsplit(envvar,"\t",0);
      i=0;

      hostnm=g_string_new("");
      qry=g_string_new("");
      pxyqry=g_string_new("");
      while(srcs[i]!=NULL)
      {
            fprintf(stderr,"HUBLIST: '%s'\n",srcs[i]);

            if(!strncmp(srcs[i],"http://",strlen("http://")))
            {
                  HUBSOURCE hs;
                  char *t;

                  g_string_assign(hostnm,srcs[i]+strlen("http://"));
                  t=strchr(hostnm->str,'/');
                  if(t==NULL)
                        goto abrt;
                  
                  /* extract the PATH from the URL */
                  g_string_sprintf(qry,"GET %s HTTP/1.1\n"
                                                            "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\n",t);

                  /* keep the host:port part */
                  g_string_truncate(hostnm,t-hostnm->str);

                  /* build the end of the query */
                  g_string_sprintfa(qry,"Host: %s\n"
                                                            "Cache-Control: no-cache\n"
                                                            "Connection: close\n"
                                                            "\n" ,hostnm->str);

                  /* the easiest part, the proxy query */
                  if((connect_type==PROXY)&&(user_id!=NULL))      /* it is a password protected proxy */
                  {
                        g_string_sprintf(pxyqry,"GET %s HTTP/1.1\n"     
                                    "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\n"    
                                    "Host: %s\n"                                    
                                    "Cache-Control: no-cache\n"                           
                                    "Connection: close\n"                                       
                                    "Authorization: Basic %s\n"
                                    "\n",srcs[i],hostnm->str,user_id);
                  }
                  else
                        g_string_sprintf(pxyqry,"GET %s HTTP/1.1\n"     
                                    "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\n"    
                                    "Host: %s\n"                                    
                                    "Cache-Control: no-cache\n"                           
                                    "Connection: close\n"                                       
                                    "\n",srcs[i],hostnm->str);

                  t=strchr(hostnm->str,':');
                  if(t==NULL)
                        hs.hostport=80;
                  else
                  {
                        hs.hostport=atoi(t+1);
                        g_string_truncate(hostnm,t-hostnm->str);
                  }
                  hs.hostname=hostnm->str;
                  hs.query=qry->str;
                  hs.proxyquery=pxyqry->str;

                  if(!strcmp(srcs[i]+strlen(srcs[i])-4,".bz2"))
                  {
#ifdef HAVE_BZIP2
                        process_bz2_hub_source(&hs,connect_type,socks_ip, socks_port,user_id,proxy_host,proxy_port);
#else
#warning BZIP2 not available. bz2 hublists will be unavailable
                        fprintf(stderr,"%s ignore because 'bzip2' is not available\n",srcs[i]);
#endif
                  }
                  else
                  {
                        process_hub_source(&hs,connect_type,socks_ip, socks_port,user_id,proxy_host,proxy_port);
                  }
            }
            abrt:
            i++;
      }

      g_string_free(hostnm,TRUE);
      g_string_free(qry,TRUE);
      g_string_free(pxyqry,TRUE);
      g_strfreev(srcs);
}

/***********************************************************/
/* download a standard hub source and display it on stdout */
/***********************************************************/
static void process_hub_source(HUBSOURCE *hs, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port)
{
      struct sockaddr_in nom; /* adresse de la socket destinataire */
      int desc;         /* descripteur de la socket cree */
      struct hostent *hp;
      char com[TAILLE];
      int i;
      long nb;

      fprintf(stderr,"Processing: %s\n",hs->hostname);
      /* creating socket */
      if((desc=socket(AF_INET,SOCK_STREAM,0))==-1)
      {
            perror("unable to create socket");
            exit(1);
      }

      /* recherche de l'adresse internet du serveur */
      if(connect_type==PROXY)
            hp=gethostbyname(proxy_host);
      else
            hp=gethostbyname(hs->hostname);

      if(hp==NULL)
      {
            fprintf(stderr,"Unable to find host address.\n");
            close(desc);
            return;
      }

      /* demande de connexion */
      for(i=0;i<3;i++)
      {
            int ret;

            /* preparing socket dest addr */
            memcpy(&nom.sin_addr,hp->h_addr,hp->h_length);
            nom.sin_family=AF_INET;
            nom.sin_port=htons(hs->hostport);
            if(connect_type==PROXY)
                  nom.sin_port=htons(atoi(proxy_port));

            ret=do_connect(desc,nom,socks_ip,socks_port,user_id,connect_type);
            if(ret!=-1)
            {
                  int eoh;
                  int have;
                  /* send the query */
                  if(connect_type==PROXY)
                  {
                        if(user_id==NULL)       /* proxy without login:passwd required */
                              send(desc,hs->proxyquery,strlen(hs->proxyquery),0);
                        else
                        {
                              GString *pppxy=g_string_new(hs->proxyquery);

                              /* remove the trailing '\n' to add the password */
                              g_string_truncate(pppxy,pppxy->len-1);
                              g_string_sprintfa(pppxy,"Authorization: Basic %s\n\n",user_id);
                              send(desc,pppxy->str,pppxy->len,0);
                              g_string_free(pppxy,TRUE);
                        }
                  }
                  else
                        send(desc,hs->query,strlen(hs->query),0);

                  /* reception of the reply block */
                  
                  /* skip html header */
                  eoh=0;
                  have=0;
                  do
                  {
                        if((recv(desc,com,1,MSG_WAITALL))<=0)
                        {
                              perror("recv");
                              close(desc);
                              return;
                        }

                        if(com[0]=='\n')
                        {
                              if(have==0)
                                    have=1;
                              else
                                    eoh=1;            /* 2 consecutives \n */
                        }
                        else if(com[0]!='\r')
                              have=0;
                  } while(eoh==0);

                  /* display body content */
                  do
                  {
                        nb=recv(desc,com,TAILLE,0);
                        if(nb>0)
                        {
                              fwrite(com,nb,1,output);
                        }
                        fflush(stderr);
                  }while(nb>0);

                  close(desc);
                  fprintf(stderr,"successful end: %s\n",hs->hostname);
                  return;
            }
      }
      perror("connect");
      close(desc);
      fprintf(stderr,"end with error: %s\n",hs->hostname);
      return;
}

#ifdef HAVE_BZIP2
/********************************************************/
/* the bzip2 list was unzip2 into the given filename    */
/* it can be either a standard hublist or a XML hublist */
/********************************************************/
static void display_bunzip2_list(const char *out_name)
{
      GError *err=NULL;
      gsize h_length;
      gchar *content;

      if(g_file_get_contents(out_name,&content,&h_length,&err)==TRUE)
      {
            if(strncmp(content,"<?xml",5))
            {
                  /* it is a standard list */
                  fwrite(content,h_length,1,stdout);
            }
            else
            {
                  /* looks like a XML hublist */
                  convert_and_print_xml_hub_list(content,h_length);
            }
            g_free(content);
      }
      else
      {
            fprintf(stderr,"Unable to load bz2 list from file: %s\n",out_name);
            g_error_free(err);
      }
}

/******************************************************/
/* download a bz2 hub source and display it on stdout */
/******************************************************/
static void process_bz2_hub_source(HUBSOURCE *hs, const int connect_type,
                                                                  const char *socks_ip, const char *socks_port,
                                                                  const char *user_id, const char *proxy_host,
                                                                  const char *proxy_port)
{
      struct sockaddr_in nom; /* adresse de la socket destinataire */
      int desc;         /* descripteur de la socket cree */
      struct hostent *hp;
      char com[TAILLE];
      int i;
      long nb;

      fprintf(stderr,"Processing: %s\n",hs->hostname);
      /* creating socket */
      if((desc=socket(AF_INET,SOCK_STREAM,0))==-1)
      {
            perror("unable to create socket");
            exit(1);
      }

      /* recherche de l'adresse internet du serveur */
      if(connect_type==PROXY)
            hp=gethostbyname(proxy_host);
      else
            hp=gethostbyname(hs->hostname);

      if(hp==NULL)
      {
            fprintf(stderr,"Unable to find host address.\n");
            close(desc);
            return;
      }

      /* demande de connexion */
      for(i=0;i<3;i++)
      {
            int ret;

            /* preparing socket dest addr */
            memcpy(&nom.sin_addr,hp->h_addr,hp->h_length);
            nom.sin_family=AF_INET;
            nom.sin_port=htons(hs->hostport);
            if(connect_type==PROXY)
                  nom.sin_port=htons(atoi(proxy_port));

            ret=do_connect(desc,nom,socks_ip,socks_port,user_id,connect_type);
            if(ret!=-1)
            {
                  int eoh;
                  int have;
                  /* send the query */
                  if(connect_type==PROXY)
                        send(desc,hs->proxyquery,strlen(hs->proxyquery),0);
                  else
                        send(desc,hs->query,strlen(hs->query),0);

                  /* reception du bloc reponse */
                  
                  /* skip html header */
                  eoh=0;
                  have=0;
                  do
                  {
                        if((recv(desc,com,1,MSG_WAITALL))<=0)
                        {
                              perror("recv");
                              close(desc);
                              return;
                        }

                        if(com[0]=='\n')
                        {
                              if(have==0)
                                    have=1;
                              else
                                    eoh=1;            /* 2 consecutives \n */
                        }
                        else if(com[0]!='\r')
                              have=0;
                  } while(eoh==0);

                  /* display body content */
                  {
                        int ppfd[2];
                        int rpid;
                        int out_fd=-1;
                        char *out_name=NULL;
                        GError *out_error=NULL;

                        if(pipe(ppfd)==-1)
                        {
                              perror("pipe");
                              close(desc);
                              fprintf(stderr,"end with error: %s\n",hs->hostname);
                              return;
                        }

                        out_fd=g_file_open_tmp("bz_hublist.XXXXXX",&out_name,&out_error);
                        if(out_fd==-1)
                        {
                              fprintf(stderr,"Unable to create temp_file.\n");
                              g_error_free(out_error);
                              close(desc);
                              close(ppfd[0]);
                              close(ppfd[1]);
                        }

                        switch(rpid=fork())
                        {
                              case -1:
                                                perror("fork");
                                                close(out_fd);
                                                unlink(out_name);
                                                close(desc);
                                                fprintf(stderr,"end with error: %s\n",hs->hostname);
                                                close(ppfd[0]);
                                                close(ppfd[1]);
                                                return;

                              case 0:     /* the son */
                                                close(ppfd[1]);
                                                dup2(ppfd[0],0);        /* redirect stdin */
                                                close(ppfd[0]);
                                                dup2(out_fd,1);         /* redirect stdout */
                                                close(out_fd);
                                                execlp("bzip2","bzip2","-cd",NULL);
                                                exit(0);

                              default:    
                                                close(ppfd[0]);
                                                close(out_fd);
                                                do
                                                {
                                                      nb=recv(desc,com,TAILLE,0);
                                                      if(nb>0)
                                                      {
                                                            write(ppfd[1],com,nb);
                                                      }
                                                      fflush(stderr);
                                                }while(nb>0);
                                                close(ppfd[1]);
                                                waitpid(rpid,NULL,0);
                                                break;
                        }
                        display_bunzip2_list(out_name);
                        unlink(out_name);
                        g_free(out_name);
                        close(desc);
                        fprintf(stderr,"successful end: %s\n",hs->hostname);
                        return;
                  }
            }
      }
      perror("connect");
      close(desc);
      fprintf(stderr,"end with error: %s\n",hs->hostname);
      return;
}
#endif

Generated by  Doxygen 1.6.0   Back to index