dist.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include "utils.h"
  5. extern char m_buffer[4096];
  6. #define BANNER "220 " HOSTNAME " SMTP"
  7. #define HELOANSWER "250 " HOSTNAME
  8. #define CMDUNKNOWN "502 command unimplemented"
  9. #define DOMAINUNKNOWN "553 unknown domain"
  10. #define TEMPERROR "421 delivery error, please retry later"
  11. #define DEFERROR "521 permanent delivery error, do not retry"
  12. #define PORT 25
  13. #define fail() do { perror(__FILE__ ":"); exit(-1); } while(0);
  14. struct serverinfo
  15. {
  16. char *address;
  17. unsigned port;
  18. };
  19. unsigned long connid=0;
  20. struct serverinfo *get_server(char *domain)
  21. {
  22. char buffer[1024];
  23. unsigned long *longs;
  24. /* connect to mysql and get values */
  25. db=mysql_init(NULL);
  26. if(NULL==mysql_real_connect(db,DBHOST,DBUSER,DBPASS,DBNAME,0,NULL,0)) { fprintf(stderr,"%s\n",mysql_error(db)); mysql_close(db); return NULL; }
  27. /* clean string */
  28. escape(db,domain);
  29. /* generate sql */
  30. snprintf(buffer,sizeof buffer,"SELECT `host`,`port` FROM `domains` WHERE `domain`=\"%s\" ORDER BY RAND();",domain);
  31. /* query! */
  32. if(mysql_query(db,buffer)) { fprintf(stderr,"%s\n",mysql_error(db)); mysql_close(db); return NULL; }
  33. for(i=0;row=mysql_fetch_row(db);i++)
  34. {
  35. longs=mysql_fetch_lengths(row);
  36. }
  37. mysql_close(db);
  38. return NULL;
  39. }
  40. char *get_domain(char *line)
  41. {
  42. char *strtmp=NULL;
  43. char *buf=NULL;
  44. safestrdup(buf,strchr(line,'@')+1);
  45. safestrdup(strtmp,strtok(buf," \"><"));
  46. condfree(buf);
  47. return strtmp;
  48. }
  49. void handle_new_connection(unsigned long p_connid,int fd)
  50. {
  51. char *buf=NULL;
  52. char *from=NULL;
  53. char *to=NULL;
  54. char *domain=NULL;
  55. char *serveraddress=NULL;
  56. int fdin=-1;
  57. int fds[2];
  58. char databuffer[8192];
  59. int bytesread;
  60. int fdread,fdwrite;
  61. struct serverinfo *server;
  62. connid=p_connid;
  63. write_string(fd,BANNER);
  64. while(!socketeof(fd))
  65. {
  66. free_and_read_string(buf,fd);
  67. if(!cmp(buf,"HELO")||!cmp(buf,"EHLO"))
  68. write_string(fd,HELOANSWER);
  69. else if(!cmp(buf,"MAIL FROM"))
  70. {
  71. safestrdup(from,buf);
  72. write_string(fd,"250 Ok");
  73. }
  74. else if(!cmp(buf,"RCPT TO"))
  75. {
  76. safestrdup(to,buf);
  77. domain=get_domain(to);
  78. if(NULL==(server=get_server(domain)))
  79. {
  80. write_string(fd,DOMAINUNKNOWN);
  81. exit(-1);
  82. }
  83. condfree(domain);
  84. break;
  85. }
  86. else
  87. write_string(fd,CMDUNKNOWN);
  88. }
  89. if(-1==(fdin=create_connected_socket(server->address,server->port)))
  90. {
  91. write_string(fd,TEMPERROR);
  92. exit(-1);
  93. }
  94. do /* manage errors as we would do an exception, all in one point */
  95. {
  96. /* reproduce initial conversation on the new server */
  97. free_and_read_string(buf,fdin); /* read banner */
  98. write_string(fdin,"HELO " HOSTNAME); do { free_and_read_string(buf,fdin); } while('-'==buf[3]);
  99. write_string(fdin,from); do { free_and_read_string(buf,fdin); } while('-'==buf[3]);
  100. if(cmp(buf,"250")) { write_string(fd,DEFERROR); break; }
  101. write_string(fdin,to);
  102. /* now just copy data from one server to the other */
  103. while(1)
  104. {
  105. fds[0]=fd; fds[1]=fdin;
  106. can_read(fds,2,-1);
  107. if(can_read(&fd,1,0)) { fdread=fd; fdwrite=fdin; }
  108. else { fdread=fdin; fdwrite=fd; }
  109. bytesread=read(fdread,databuffer,sizeof(databuffer));
  110. if(bytesread<=0||write(fdwrite,databuffer,bytesread)<=0)
  111. {
  112. closeskt(fd);
  113. closeskt(fdin);
  114. break;
  115. }
  116. }
  117. }
  118. while(0);
  119. condfree(buf); condfree(to); condfree(from); closeskt(fd); closeskt(fdin);
  120. exit(0);
  121. }
  122. int main(int argc, char **argv)
  123. {
  124. int fd_server=-1,fd=-1;
  125. unsigned long conn=0;
  126. /* ignore dying child */
  127. signal(SIGCHLD,SIG_IGN);
  128. openlog("dist",0,LOG_MAIL);
  129. if(-1==(fd_server=create_listening_socket(PORT))) fail();
  130. while(-1!=(fd=accept(fd_server,NULL,0)))
  131. {
  132. debug("New connection!");
  133. ++conn;
  134. switch(fork())
  135. {
  136. case 0: closeskt(fd_server); handle_new_connection(conn,fd);
  137. case -1: fail();
  138. default: closeskt(fd);
  139. }
  140. }
  141. close(fd_server);
  142. closelog();
  143. exit(0);
  144. }