#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/select.h>
#define DO 0xfd
#define WONT 0xfc
#define WILL 0xfb
#define DONT 0xfe
#define CMD 0xff
#define CMD_ECHO 1
#define CMD_WINDOW_SIZE 31
#define BUFLEN 20096
//#define BUFLEN 20
int len;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <pthread.h>
#define RESET "\033[0m"
#define RED "\033[1;31m"
#define GREEN "\033[1;32m"
#define YELLOW "\033[1;33m"
#define BLUE "\033[1;34m"
#define CYAN "\033[1;36m"
#define BOLD "\033[1m"
// Kolorowe printf-y
#define info(...) printf(GREEN __VA_ARGS__); printf(RESET)
#define warn(...) printf(YELLOW __VA_ARGS__); printf(RESET)
#define err(...) fprintf(stderr, RED __VA_ARGS__); fprintf(stderr, RESET)
#define debug(...) printf(CYAN __VA_ARGS__); printf(RESET)
#define START_PORT 1
#define END_PORT 1024
#define TIMEOUT_SEC 0
#define TIMEOUT_USEC 200000 // 200ms
const char *target_ip;
void *scan_port(void *arg) {
int port = *(int *)arg;
free(arg);
int sockfd;
struct sockaddr_in target;
struct timeval timeout;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) pthread_exit(NULL);
timeout.tv_sec = TIMEOUT_SEC;
timeout.tv_usec = TIMEOUT_USEC;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
target.sin_family = AF_INET;
target.sin_port = htons(port);
target.sin_addr.s_addr = inet_addr(target_ip);
int result = connect(sockfd, (struct sockaddr *)&target, sizeof(target));
if (result == 0) {
printf("Port %d jest OTWARTY\n", port);
}
close(sockfd);
pthread_exit(NULL);
}
int scan(int argc, char *argv[]) {
if (argc != 2) {
printf("Użycie: %s <IP>\n", argv[0]);
return 1;
}
target_ip = argv[1];
printf(GREEN,"Skanowanie hosta %s w zakresie portów %d-%d...\n", target_ip, START_PORT, END_PORT);
pthread_t threads[END_PORT - START_PORT + 1];
int thread_count = 0;
for (int port = START_PORT; port <= END_PORT; port++) {
int *arg = (int *)malloc(sizeof(int));
if (!arg) {
perror("malloc");
continue;
}
*arg = port;
if (pthread_create(&threads[thread_count], NULL, scan_port, arg) != 0) {
perror("pthread_create");
free(arg);
} else {
thread_count++;
}
}
// Poczekaj na zakończenie wszystkich wątków
for (int i = 0; i < thread_count; i++) {
pthread_join(threads[i], NULL);
}
printf("Skanowanie zakończone.\n");
return 0;
}
unsigned char buf[BUFLEN + 1];
static struct termios tin;
int hostname_to_ip(char *hostname, char *ip) {
struct hostent *he;
struct in_addr **addr_list;
if ((he = gethostbyname(hostname)) == NULL) {
herror("gethostbyname");
return 1;
}
addr_list = (struct in_addr **)he->h_addr_list;
int i = 0;
while (addr_list[i] != NULL) {
printf(GREEN,"IP[%d]: %s\n", i, inet_ntoa(*addr_list[i]));
i++;
}
// Zwróć pierwszy IP jako główny
if (addr_list[0] != NULL) {
strcpy(ip, inet_ntoa(*addr_list[0]));
return 0;
}
return 1;
}
int hostname_to_ip2(char *hostname, char *ip) {
struct hostent *he;
struct in_addr **addr_list;
if ((he = gethostbyname(hostname)) == NULL) {
herror("gethostbyname");
return 1;
}
addr_list = (struct in_addr **)he->h_addr_list;
if (addr_list[0] != NULL) {
strcpy(ip, inet_ntoa(*addr_list[0]));
return 0;
printf("%s",inet_ntoa(*addr_list[1]));
}
printf(GREEN,"%s",inet_ntoa(*addr_list[0]));
return 1;
}
void parse_passive_mode(char *response, char *ip, int *port) {
int a, b, c, d, e, f;
if (sscanf(response, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", &a, &b, &c, &d, &e, &f) == 6) {
sprintf(ip, "%d.%d.%d.%d", a, b, c, d);
*port = (e * 256) + f;
}
}
void negotiate(int sock, unsigned char *buf, int len) {
int i;
if (buf[1] == DO && buf[2] == CMD_WINDOW_SIZE) {
unsigned char tmp1[10] = {255, 251, 31};
if (send(sock, tmp1, 3 , 0) < 0) exit(1);
unsigned char tmp2[10] = {255, 250, 31, 0, 80, 0, 24, 255, 240};
if (send(sock, tmp2, 9, 0) < 0) exit(1);
return;
}
for (i = 0; i < len; i++) {
if (buf[i] == DO) buf[i] = WONT;
else if (buf[i] == WILL) buf[i] = DONT;
}
if (send(sock, buf, len , 0) < 0) exit(1);
}
//static struct termios tin;
static void terminal_set(void) {
tcgetattr(STDIN_FILENO, &tin);
static struct termios tlocal;
memcpy(&tlocal, &tin, sizeof(tin));
cfmakeraw(&tlocal);
tcsetattr(STDIN_FILENO, TCSANOW, &tlocal);
}
static void terminal_reset(void) {
tcsetattr(STDIN_FILENO, TCSANOW, &tin);
}
void parse_url(char *url, char *hostname, char *path, int *port) {
char *p = url;
char *protocol_end;
// Domyślnie: HTTP
*port = 80;
if (strstr(p, "ftp://") == p) {
*port = 21;
protocol_end = p + strlen("ftp://");
} else if (strstr(p, "http://") == p) {
*port = 80;
protocol_end = p + strlen("http://");
} else if (strstr(p, "https://") == p) {
fprintf(stderr, "Protokół HTTPS nie jest wspierany (brak TLS)\n");
exit(1);
} else {
protocol_end = p;
}
char *host_end = strchr(protocol_end, '/');
if (host_end != NULL) {
strncpy(hostname, protocol_end, host_end - protocol_end);
hostname[host_end - protocol_end] = '\0';
strcpy(path, host_end);
} else {
strcpy(hostname, protocol_end);
strcpy(path, "/");
}
}
void usage(char *prog_name) {
printf(GREEN,"Użycie: %s URL [PORT] [opcje]\n", prog_name);
printf("Argumenty:\n");
printf(" URL Adres URL lub host (np. http://host lub ftp.gnu.org)\n");
printf(" PORT Port TCP (opcjonalny, domyślnie 80)\n");
printf("Opcje:\n");
printf(" -s Włącza skanowanie portów 1-1024 dla podanego hosta\n");
printf(" -m METHOD Metoda HTTP (GET, POST, PUT, HEAD, OPTIONS). Domyślnie: GET\n");
printf(" -b BODY Ciało żądania dla POST/PUT\n");
printf(" -h Wyświetla tę pomoc\n");
printf("\nPrzykłady:\n");
printf(" %s http://example.com -m GET\n", prog_name);
printf(" %s ftp.gnu.org -s\n", prog_name);
printf(" %s smtp.gmail.com 587\n", prog_name);
}
int main(int argc, char *argv[]) {
int sock;
struct sockaddr_in server;
char ip_str[INET_ADDRSTRLEN];
int port;
char*location[100];
char hostname[256];
char *url = NULL;
char *body = NULL;
char path[BUFLEN];
char *method = "GET";
int scan_mode = 0;
int bytes_received;
// char *path = "/";
char http_request[4006];
char*hearth[100];
int data_sock = socket(AF_INET, SOCK_STREAM, 0);
if (argc < 2) {
fprintf(stderr, "Brak URL-a!\n");
usage(argv[0]);
return 1;
}
// PARSOWANIE ARGUMENTÓW POZYCYJNYCH: URL + PORT (opcjonalny)
int arg_index = 1;
url = argv[arg_index++];
parse_url(url, hostname, path, &port); // ⬅️ najpierw parsuj URL i ustaw domyślny port
if (arg_index < argc && argv[arg_index][0] != '-') {
int custom_port = atoi(argv[arg_index++]);
if (custom_port <= 0 || custom_port > 65535) {
fprintf(stderr, "Nieprawidłowy port: %s\n", argv[arg_index - 1]);
return 1;
}
port = custom_port; // ⬅️ nadpisz tylko jeśli użytkownik podał jawnie
}
// Przestawienie argv tak, żeby getopt przetwarzał od prawidłowego miejsca
optind = arg_index;
int c;
while ((c = getopt(argc, argv, "m:b:sh")) != -1) {
switch (c) {
case 's':
scan_mode = 1;
break;
case 'm':
method = optarg;
break;
case 'b':
body = optarg;
break;
case 'h':
usage(argv[0]);
return 0;
case '?':
fprintf(stderr, "Nieznana opcja: -%c\n", optopt);
usage(argv[0]);
return 1;
}
}
// Parsowanie URL
// parse_url(url, hostname, path, &port);
printf("Parsed - Host: %s, Path: %s, Port: %d\n", hostname, path, port);
if (hostname_to_ip(hostname, ip_str) != 0) {
fprintf(stderr, "Nie mozna rozwiazac nazwy hosta: %s\n", hostname);
return 1;
}
if (scan_mode) {
char *scan_argv[] = { argv[0], ip_str };
return scan(2, scan_argv); // wywołuje funkcję skanera i kończy program
}
// Tworzenie i łączenie gniazda
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Could not create socket. Error");
return 1;
}
server.sin_addr.s_addr = inet_addr(ip_str);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connect failed. Error");
return 1;
}
puts("Connected...\n");
FILE *fp = fopen("index.html", "w");
if (fp == NULL) {
perror("Error opening file");
close(sock);
return 1;
}
/* sprintf(http_request, "%s %s HTTP/1.1\r\nHost:%s\r\nConnection:close\r\n\r\n", method, path, hostname);*/
if (strcasecmp(method, "POST") == 0 || strcasecmp(method, "PUT") == 0) {
if (body == NULL) {
body = ""; // żeby nie było NULL
}
sprintf(http_request,
"%s %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n"
"\r\n"
"%s",
method, path, hostname, strlen(body), body);
} else if (strcasecmp(method, "DELETE") == 0) {
sprintf(http_request,
"DELETE %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n",
path, hostname);
} else {
sprintf(http_request,
"%s %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n",
method, path, hostname);
}
printf("%s",http_request);
struct timeval ts;
ts.tv_sec = 1;
ts.tv_usec = 0;
while (1) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
FD_SET(0, &fds);
if (data_sock != -1) FD_SET(data_sock, &fds);
int max_fd = (data_sock > sock) ? data_sock : sock;
int nready = select(max_fd + 1, &fds, (fd_set *)0, (fd_set *)0, &ts);
if (nready < 0) {
perror("select. Error");
return 1;
} else if (nready == 0) {
ts.tv_sec = 1;
ts.tv_usec = 0;
}
if (port==80){
send(sock, http_request, strlen(http_request), 0);
}
// Obsługa danych z gniazda kontrolnego (sock)
if (FD_ISSET(sock, &fds)) {
int rv = recv(sock, buf, sizeof(buf) - 1, 0);
if (rv > 0) {
buf[rv] = '\0';
printf("%s", buf);
fprintf(fp,"%s",buf);
fflush(stdout);
if (strstr((char *)buf, "HTTP/1.1 301") != NULL) {
char *location_start = strstr((char *)buf, "Location:");
if (location_start) {
location_start += strlen("Location:");
while (*location_start == ' ') location_start++; // pomiń spacje
char new_url[BUFLEN];
int i = 0;
while (*location_start && *location_start != '\r' && *location_start != '\n' && i < BUFLEN - 1) {
new_url[i++] = *location_start++;
}
new_url[i] = '\0';
printf(YELLOW "301 Moved Permanently ➡️ Przekierowanie na: %s\n" RESET, new_url);
close(sock);
if (data_sock != -1) close(data_sock);
fclose(fp);
char *new_argv[] = { argv[0], new_url };
printf(YELLOW "▶️ Wznawiam żądanie pod nowym adresem...\n" RESET);
return main(2, new_argv); // rekurencyjnie wywołaj main z nowym URL
}
}
// Sprawdzamy, czy odebrana wiadomość to odpowiedź na PASV
if (strstr((char *)buf, "227 Entering Passive Mode") != NULL) {
char data_ip[INET_ADDRSTRLEN];
int data_port;
parse_passive_mode((char *)buf, data_ip, &data_port);
data_sock = socket(AF_INET, SOCK_STREAM, 0);
if (data_sock < 0) {
perror("socket (data)");
data_sock = -1;
continue;
}
struct sockaddr_in data_server_addr;
data_server_addr.sin_family = AF_INET;
data_server_addr.sin_port = htons(data_port);
inet_pton(AF_INET, data_ip, &data_server_addr.sin_addr);
if (connect(data_sock, (struct sockaddr *)&data_server_addr, sizeof(data_server_addr)) < 0) {
perror("connect (data socket)");
close(data_sock);
data_sock = -1;
}
}
} else if (rv == 0) {
printf("Connection closed by the remote end\n\r");
break;
} else {
perror("recv");
break;
}
}
// Obsługa danych z gniazda danych (data_sock)
if (data_sock != -1 && FD_ISSET(data_sock, &fds)) {
int rv = recv(data_sock, buf, sizeof(buf) - 1, 0);
if (rv > 0) {
buf[rv] = '\0';
printf("%s", buf);
} else {
close(data_sock);
data_sock = -1;
printf("\n--- Zakonczono transfer danych ---\n");
}
}
// Obsługa danych z klawiatury
if (FD_ISSET(0, &fds)) {
char input_buffer[BUFLEN];
if (fgets(input_buffer, sizeof(input_buffer), stdin) == NULL) break;
// Usunięcie znaku nowej linii
input_buffer[strcspn(input_buffer, "\n")] = 0;
if (strcmp(input_buffer, "quit") == 0) {
char quit_cmd[] = "QUIT\r\n";
send(sock, quit_cmd, strlen(quit_cmd), 0);
break;
}
// Wysyłanie komendy do serwera, kończąc ją CRLF
char full_cmd[BUFLEN + 2];
sprintf(full_cmd, "%s\r\n", input_buffer);
if (send(sock, full_cmd, strlen(full_cmd), 0) < 0) {
perror("send");
continue;
}
}
}
fclose(fp);
puts("save in index.html");
if (sock != -1) close(sock);
if (data_sock != -1) close(data_sock);
return 0;
}