⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtpr.c

📁 A simple smtp relay server. Which follows smtp protocol correctly. It receive an email. and relay it
💻 C
📖 第 1 页 / 共 2 页
字号:
  static char *special_characters = "()<>@,;:\\\"[]";
   /* validate name  */
  for (a = address;  *a;  a++) {
    if (*a == '\"' && (a == address || *(a - 1) == '.' || *(a - 1) == 
        '\"')) {
      while (*++a) {
        if (*a == '\"') break;
        if (*a == '\\' && (*++a == ' ')) continue;
        if (*a <= ' ' || *a >= 127) return 0;
      }
      if (!*a++) return 0;
      if (*a == '@') break;
      if (*a != '.') return 0;
      continue;
    }
    if (*a == '@') break;
    if (*a <= ' ' || *a >= 127) return 0;
    if (strchr(special_characters, *a)) return 0;
  }
  if (a == address || *(a - 1) == '.') return 0;

  /* next we validate the host portion (name@host) */
  if (!*(host = ++a)) return 0;
  do {
    if (*a == '.') {
      if (a == host || *(a - 1) == '.') return 0;
      number++;
    }
    if (*a <= ' ' || *a >= 127) return 0;
    if (strchr(special_characters, *a)) return 0;
  } while (*++a);

  return (number >= 1);
}

int main(int argc, char *argv[])
{
	int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct sockaddr_in my_addr;    // my address information
    struct sockaddr_in their_addr; // connector's address information
    int sin_size;
    int yes=1;
    socklen_t addr_len;
    int numbytes=0;
    char buf[MAXBUFLEN] = "";
    char tmp_msg[MAXBUFLEN] ="";
    char message[SQMAXDATASIZE];
    char message_buf[10000];
    char *msg = message;
    char quit[MAXBUFLEN];
    int MYPORT;
    char relay[RELAY_NAME];
    int i,j;
    char *email = NULL;
    char *email2 = NULL;
    char *mail_from = NULL;
    char *mail_to = NULL;
    char *tmp_mail = NULL;
    char mailtos[2000];
    int mailto_num =0;
    char *data = NULL;
    char *data2 = NULL;
    char *quit1 = NULL;
    char *quit2 = NULL;

    

    int state1 = 0;  //  
    int state2 = 0;  //  keep track of number of 'helo's
        int logwhile = 0;
    char hardcode_email[15] = "cylaw@cs.hku.hk";


    #ifdef WIN32
      WSADATA wsaData;
      WSAStartup(0x0101, &wsaData);
    #endif

    /* check number of parameters */
    if ( argc != 3 && argc !=2 ) {
		fprintf(stderr,"usage: smtpr <port number> (<relay server>)\n");
		exit(1);
    }
    
    /* fill in port number */
    MYPORT = atoi(argv[1]);
    if ( MYPORT <= 0){
	fprintf(stderr, "Invalid port number.\nusage: smtpr <port number> (<relay server>)\n");
        exit(1);
    }

    /* fill in the server relay to */
    if (argc == 2) strcpy(relay, "some.mail.server");
    else if (argc == 3) strcpy(relay, argv[2]);
    printf("relay to %s\n", relay);


/*create a TCP socket */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    
    printf("port number : %i\n", MYPORT);

    my_addr.sin_family = AF_INET;         // host byte order
    my_addr.sin_port = htons(MYPORT);     // short, network byte order
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // automatically fill with my IP
    memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

/* bind to the port number*/
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }
/* listen*/
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }  
    

    /* slow the receiving speed */
//    sleep(1);
    
while(1){

logwhile++;


switch ( state1 ){
	
case ACCEPT:
/* accept */
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
            perror("accept");
        }
        printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
       
/* send msg : 220 */       
       if (send(new_fd, "220 cylaw's smtpr ready\r\n", 25, 0) == -1)
            perror("send");


/*proceed to next state*/
        printf("state1 = %i\n", state1);
        state1++;
				break;

case HELO:

						if(state2 == 0){	//state2 keep track of if this is the first HELO
		        if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
		            perror("recv");
		            exit(1);
  		      }
  		    }
      		  buf[numbytes] = '\0';

/*   log   */	
				printf("case HELO\n");
				printf("============\n");
        printf("buf :%s\n", buf);

/* check on length */
        if ( strlen(buf) < 6 || strlen(buf) > MAXDATASIZE ){
        					printf("550 Syntax: <HELO>\n");
									if (send(new_fd, "550 Syntax: <HELO|EHLO> <hostname>\r\n", 36, 0) == -1)
									perror("HELO send");
        	}
        
/* compare (case-insensitively) the first 4 bytes of buf with "HELO" and "EHLO"  */

        if ( (strncasecmp(buf, "HELO ", 5) != 0) && (strncasecmp(buf, "EHLO ", 5) != 0 )  ){
        					printf("550 Syntax: <HELO>\n");
									if (send(new_fd, "550 Syntax: <HELO|EHLO> <hostname>\r\n", 36, 0) == -1)
									perror("HELO-1 send");
        	}
        	
/* not implement case : helo<space>aaaaa<space> */
        if ( buf[5] == '\0' && buf[5] == ' ' ){
        					printf("550 Syntax: <HELO|EHLO> <hostname>\n");
									if (send(new_fd, "550 Syntax: <HELO|EHLO> <hostname>\r\n", 36, 0) == -1)
									perror("HELO-2 send");
        	}
        
/* send 250 OK */
				printf("250 HELO OK\n");
        if ( send( new_fd, "250 HELO OK\r\n", 13, 0 ) == -1 )
        perror("HELO-250-OK send");
        printf("\n");
        


/*proceed to next state*/
        state1++;
        state2++;
        break; //case HELO

case MAILFROM :

        if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
            perror("recv");
            exit(1);
        }
        buf[numbytes] = '\0';


/*   log   */	
        printf("\n");
				printf("case MAILFROM\n");
				printf("=============\n");
        printf("buf :%s\n", buf);



/* HELO */
				if ( (strncasecmp(buf, "HELO ", 5) == 0) || (strncasecmp(buf, "EHLO ", 5) == 0 )  ){
				printf("HELO received at case MAILFROM, go back to case HELO\n");
					state1--;
					break;
				}
				
/*  check "MAIL FROM:"   */
        if ( strncasecmp(buf, "MAIL FROM:", 10) != 0 ){
        					printf("550 Syntax: MAIL FROM: <email-address>\n");
									if (send(new_fd, "550 Syntax: MAIL FROM: <email-address>\r\n", 40, 0) == -1)
											perror("MAIL FROM: send()");
								  exit(1);
       	}

/*  extract email address  */
    mail_from = extractemail(buf, 10);

     
/*  check email validity  */  

        if ( check_email_validity(mail_from) == 0 ){  //0 - invalid 1 - valid
        					printf("550 Invalid email address\r\n");
									if (send(new_fd, "550 Invalid email address\r\n", 27, 0) == -1)
										perror("Email address send()");
									break; //case MAILFROM
									
        	}

/* send 250 OK */
				printf("250 MAIL FROM OK\n");
        if ( send( new_fd, "250 MAIL FROM OK\r\n", 18, 0 ) == -1 )
        perror("MAILFROM-250-OK send()");
        
        printf("\n");

        state1++;
        break; //case MAILFROM

case RCPTTO :

/*  check if this is the first MAIL FROM: <> line  */
if ( mailto_num == 0){  
        if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
            perror("recv");
            exit(1);
        }
        buf[numbytes] = '\0';
}


/*   log   */	
        printf("\n");
				printf("case RCPTTO\n");
				printf("=============\n");
        printf("state1 = %i\n", state1);
        printf("buf :%s\n", buf);

        
/*  check RCPT TO: <...>   */
        if ( strncasecmp(buf, "RCPT TO:", 8) != 0 ){
        					printf("550 Syntax: RCPT TO: <email-address>\n");
        					if (send(new_fd, "550 Syntax: RCPT TO: <email-address>\r\n", 38, 0) == -1)
									perror("MAIL FROM: send()");
       	}

/*  extract email address  */
			mail_to = extractemail(buf, 8);  // 8 = strlen("RPCT TO:")


/*  recipients address on to mailtos []*/
		strcat(mailtos, mail_to);
		strcat(mailtos, ",");
		mailto_num++;
		printf("mailtos %s\n", mailtos);
		printf("mailto_num %i\n", mailto_num);


     	
/*  check email validity  */  

        if ( check_email_validity(mail_to) == 0 ){
        					printf("550 Invalid email address\n");
									if (send(new_fd, "550 Invalid email address\r\n", 27, 0) == -1)
									perror("RCPTTO address send()");
									break; //case MAILFROM
									
        	}

/* send 250 OK */
				printf("250 RCPT TO OK\n");
        if ( send( new_fd, "250 RCPT TO OK\r\n", 16, 0 ) == -1 )
        perror("MAILFROM-250-OK send()");

        state1++;
				break; // case RCPTTO

case DATA :

        if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
            perror("recv");
            exit(1);
        }
        buf[numbytes] = '\0';


					/*   log   */	
        printf("\n");
				printf("case DATA\n");
				printf("=============\n");
        printf("state1 = %i\n", state1);
        printf("buf :%s\n", buf);


/*  multiple recipients */

				if ( strncasecmp(buf, "RCPT TO:", 8 ) == 0){
					printf("Multiple recipients -- Go back to state RCPT TO\n");
					printf("\n");
					state1--;
					break;
				}
        
        if ( strncasecmp(buf,"DATA", 4) != 0 ){  
        					printf("451 Syntax: DATA\n");      
									if (send(new_fd, "451 Syntax: DATA\r\n", 18, 0) == -1)
										perror("DATA send");
        	} else{
				


/* send 354 OK */
//				send( new_fd, "354 End\r\n", 10, 0 );
				printf("354 End data with <CR><LF>.<CR><LF>\n");
        if ( send( new_fd, "354 End data with <CR><LF>.<CR><LF>\r\n", 37, 0 ) == -1 ){
	        perror("MAILFROM-354-OK send()");
	        printf("354 error\n");
	        exit(1);
	      }
   
        printf("\n");
      }


  state1++;
	break; // case DATA


case MESSAGE :

	      printf("\n");
				printf("case MESSAGE\n");
				printf("============\n");

				i=0;
				while(i<10000){
					i++;
        	if ((numbytes=recv(new_fd, message_buf, 9999, 0)) == -1) {
          	  perror("recv");
            	exit(1);
	        }
  	      message_buf[numbytes] = '\0';
/*  log  */
//  	      printf("message_buf:\n\n%s", message_buf);        
/*  append message_buf to message  */  	      
    	    strcat(message, message_buf);

        	if (strstr (message_buf, "\r\n.\r\n") != NULL ){
/* send 250 OK */
        		printf(". found\n");
	        	if ( send( new_fd, "250 message received\r\n", 22, 0 ) == -1 )
	  	    			  perror("MESSAGE");
        		printf("message:\n\n %s\n", message);
        		state1++;
						break;
        	}//if()
      	}//while()
      	state1++;
      	break;

case QUIT :
        
        if ((numbytes=recv(new_fd, quit, MAXDATASIZE, 0)) == -1) {
            perror("recv");
            exit(1);
        }
        quit[numbytes] = '\0';

					/*   log   */	
				printf("\n");
				printf("case QUIT\n");
				printf("=============\n");
        printf("buf :%s\n", quit);
        printf("\n");

				/*  trim space "     QUIT       "  */				
//        quit1 = malloc(strlen(quit));
//        strcpy(quit1, quit);
//        printf("quit :%s\n", quit1);
//        quit2 = trim_space(quit1);
//        printf("quit :%s\n", quit1);
        
        
/*  check QUIT   */
        if ( strncasecmp(quit, "QUIT", 4) != 0 ){
        					state1 = 	QUIT;
									if (send(new_fd, "550 Syntax: QUIT\r\n", 18, 0) == -1)
									perror("QUIT");
       	}else{
								
/* send 221 OK */
        if ( send( new_fd, "221 QUIT.\r\n", 11, 0 ) == -1 )
        perror("QUIT");
printf("QUIT!\n");
closesocket(new_fd);
state1++;
break;
}
	break; // case QUIT
	
case RELAY :
		relaymail(relay,mail_from,mailtos,mailto_num, msg);
		
		/* go back to ACCEPT states  */
		state1 = ACCEPT;  

/* reset variables  */
		strcpy(buf, "");
		strcpy(tmp_msg, "");
		strcpy(message, "");
    strcpy(message_buf, "");
		strcpy(quit,"");
    i=0;j=0;
    email = NULL;
    email2 = NULL;
    mail_from = NULL;
    mail_to = NULL;
    tmp_mail = NULL;
		strcpy(mailtos, "");
    mailto_num =0;
    data = NULL;
    data2 = NULL;
    quit1 = NULL;
    quit2 = NULL;
		state2 = 0;
		
break;
        
default : break;

}//switch
} // while(1)

        close(new_fd);
    
    #ifdef WIN32
      WSACleanup();
    #endif

    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -