📄 icmp-socket.c
字号:
/* * icmp-socket.c - ICMP socket implementations * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This 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, or (at your option) * any later version. * * This software 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 package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: icmp-socket.c,v 1.17 2001/09/19 09:49:18 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE#include <assert.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <errno.h>#include <fcntl.h>#include <time.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h># include <netinet/in.h>#endif#ifdef __MINGW32__# include <winsock2.h># include <process.h>#endif#include "libserveez/snprintf.h"#include "libserveez/util.h"#include "libserveez/socket.h"#include "libserveez/core.h"#include "libserveez/server-core.h"#include "libserveez/icmp-socket.h"#include "libserveez/raw-socket.h"#include "libserveez/server.h"/* Text representation of ICMP type codes. */static char *svz_icmp_request[] = { "echo reply", NULL, NULL, "destination unreachable", "source quench", "redirect (change route)", NULL, NULL, "echo request", NULL, NULL, "time exceeded", "parameter problem", "timestamp request", "timestamp reply", "information request", "information reply", "address mask request", "address mask reply"};#ifdef __MINGW32__/* * Microsoft discourages the use of their ICMP.DLL API, but it seems * to be the only way to make use of raw sockets anyway. The API is * almostly unusable because: * 1. you cannot receive if not previously sent a packet * 2. the IcmpSendEcho call is blocking * 3. receive and send is one call * 4. you cannot set the ICMP header (type, code) *//* * Note 2: For the most part, you can refer to RFC 791 for details * on how to fill in values for the IP option information structure. */typedef struct ip_option_information{ unsigned char Ttl; /* Time To Live (used for traceroute) */ unsigned char Tos; /* Type Of Service (usually 0) */ unsigned char Flags; /* IP header flags (usually 0) */ unsigned char OptionsSize; /* Size of options data (usually 0, max 40) */ unsigned char *OptionsData; /* Options data buffer */}IPINFO;/* * Note 1: The Reply Buffer will have an array of ICMP_ECHO_REPLY * structures, followed by options and the data in ICMP echo reply * datagram received. You must have room for at least one ICMP * echo reply structure, plus 8 bytes for an ICMP header. */typedef struct icmp_echo_reply{ unsigned long Address; /* source address */ unsigned long Status; /* IP status value (see below) */ unsigned long RTTime; /* Round Trip Time in milliseconds */ unsigned short DataSize; /* reply data size */ unsigned short Reserved; /* */ void *Data; /* reply data buffer */ IPINFO Options; /* reply options */}ICMPECHO;/* * DLL function definitions of IcmpCloseHandle, IcmpCreateFile, * IcmpParseReplies, IcmpSendEcho and IcmpSendEcho2. */typedef HANDLE (__stdcall * IcmpCreateFileProc) (void);typedef BOOL (__stdcall * IcmpCloseHandleProc) (HANDLE IcmpHandle);typedef DWORD (__stdcall * IcmpSendEchoProc) ( HANDLE IcmpHandle, /* handle returned from IcmpCreateFile() */ unsigned long DestAddress, /* destination IP address (in network order) */ void *RequestData, /* pointer to buffer to send */ unsigned short RequestSize, /* length of data in buffer */ IPINFO *RequestOptns, /* see Note 2 */ void *ReplyBuffer, /* see Note 1 */ unsigned long ReplySize, /* length of reply (at least 1 reply) */ unsigned long Timeout /* time in milliseconds to wait for reply */);/* * Error definitions. */#define IP_STATUS_BASE 11000#define IP_SUCCESS 0#define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1)#define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2)#define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3)#define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4)#define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5)#define IP_NO_RESOURCES (IP_STATUS_BASE + 6)#define IP_BAD_OPTION (IP_STATUS_BASE + 7)#define IP_HW_ERROR (IP_STATUS_BASE + 8)#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9)#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10)#define IP_BAD_REQ (IP_STATUS_BASE + 11)#define IP_BAD_ROUTE (IP_STATUS_BASE + 12)#define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13)#define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14)#define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15)#define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16)#define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17)#define IP_BAD_DESTINATION (IP_STATUS_BASE + 18)#define IP_ADDR_DELETED (IP_STATUS_BASE + 19)#define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20)#define IP_MTU_CHANGE (IP_STATUS_BASE + 21)#define IP_UNLOAD (IP_STATUS_BASE + 22)#define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50)#define MAX_IP_STATUS IP_GENERAL_FAILURE#define IP_PENDING (IP_STATUS_BASE + 255)/* Functions and handles for the ICMP.DLL API. */static IcmpCreateFileProc IcmpCreateFile = NULL;static IcmpCloseHandleProc IcmpCloseHandle = NULL;static IcmpSendEchoProc IcmpSendEcho = NULL;static HANDLE IcmpHandle = NULL;static HANDLE hIcmp = INVALID_HANDLE_VALUE;/* * Load the @file{ICMP.DLL} library into process address space and get all * necessary function pointers. */voidsvz_icmp_startup (void){ /* load library */ if ((IcmpHandle = LoadLibrary ("ICMP.DLL")) == NULL) { svz_log (LOG_ERROR, "icmp: LoadLibrary: %s\n", SYS_ERROR); return; } /* obtain functions */ IcmpCreateFile = (IcmpCreateFileProc) GetProcAddress (IcmpHandle, "IcmpCreateFile"); IcmpCloseHandle = (IcmpCloseHandleProc) GetProcAddress (IcmpHandle, "IcmpCloseHandle"); IcmpSendEcho = (IcmpSendEchoProc) GetProcAddress (IcmpHandle, "IcmpSendEcho"); if (IcmpSendEcho == NULL || IcmpCloseHandle == NULL || IcmpCreateFile == NULL) { svz_log (LOG_ERROR, "icmp: GetProcAddress: %s\n", SYS_ERROR); FreeLibrary (IcmpHandle); IcmpHandle = NULL; return; } /* open ping service */ if ((hIcmp = IcmpCreateFile ()) == INVALID_HANDLE_VALUE) { svz_log (LOG_ERROR, "IcmpCreateFile: %s\n", SYS_ERROR); FreeLibrary (IcmpHandle); IcmpHandle = NULL; return; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp services successfully initialized\n");#endif}/* * Shutdown the ping service. */voidsvz_icmp_cleanup (void){ /* close ip service */ if (hIcmp != INVALID_HANDLE_VALUE) { if (!IcmpCloseHandle (hIcmp)) svz_log (LOG_ERROR, "IcmpCloseHandle: %s\n", SYS_ERROR); } /* release ICMP.DLL */ if (IcmpHandle) { FreeLibrary (IcmpHandle); IcmpHandle = NULL; }}#endif /* __MINGW32__ *//* Static buffer for ip packets. */static char svz_icmp_buffer[IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMP_MSG_SIZE];/* * Get ICMP header from plain data. */static svz_icmp_header_t *svz_icmp_get_header (svz_uint8_t *data){ static svz_icmp_header_t hdr; unsigned short uint16; hdr.type = *data++; hdr.code = *data++; memcpy (&uint16, data, SIZEOF_UINT16); hdr.checksum = ntohs (uint16); data += SIZEOF_UINT16; memcpy (&uint16, data, SIZEOF_UINT16); hdr.ident = ntohs (uint16); data += SIZEOF_UINT16; memcpy (&uint16, data, SIZEOF_UINT16); hdr.sequence = ntohs (uint16); data += SIZEOF_UINT16; memcpy (&uint16, data, SIZEOF_UINT16); hdr.port = uint16; return &hdr;}/* * Create ICMP header (data block) from given structure. */static svz_uint8_t *svz_icmp_put_header (svz_icmp_header_t *hdr){ static svz_uint8_t buffer[ICMP_HEADER_SIZE]; svz_uint8_t *data = buffer; unsigned short uint16; *data++ = hdr->type; *data++ = hdr->code; uint16 = htons (hdr->checksum); memcpy (data, &uint16, SIZEOF_UINT16); data += SIZEOF_UINT16; uint16 = htons (hdr->ident); memcpy (data, &uint16, SIZEOF_UINT16); data += SIZEOF_UINT16; uint16 = htons (hdr->sequence); memcpy (data, &uint16, SIZEOF_UINT16); data += SIZEOF_UINT16; uint16 = hdr->port; memcpy (data, &uint16, SIZEOF_UINT16); return buffer;}#define ICMP_ERROR -1#define ICMP_DISCONNECT -2/* * Parse and check IP and ICMP header. Return the amount of leading bytes * to be truncated. Return ICMP_ERROR on packet errors and return * ICMP_DISCONNECT when we received an disconnection signal. */static intsvz_icmp_check_packet (svz_socket_t *sock, svz_uint8_t *data, int len){ int length; svz_uint8_t *p = data; svz_icmp_header_t *header; /* First check the IP header. */ if ((length = svz_raw_check_ip_header (p, len)) == -1) return ICMP_ERROR; /* Get the actual ICMP header. */ header = svz_icmp_get_header (p + length); p += length + ICMP_HEADER_SIZE; len -= length + ICMP_HEADER_SIZE; /* Do these checks only if it is the right kind of packet. */ if (header->type == sock->itype) { /* validate the ICMP data checksum */ if (header->checksum != svz_raw_ip_checksum (p, len)) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp: invalid data checksum\n");#endif return ICMP_ERROR; } /* check the ICMP header identification */ if (header->ident == getpid () + sock->id) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp: rejecting native packet\n");#endif return ICMP_ERROR; } /* check ICMP remote port */ if ((header->port != sock->remote_port) && !(sock->flags & SOCK_FLAG_LISTENING)) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp: rejecting filtered packet\n");#endif return ICMP_ERROR; } sock->remote_port = header->port; } /* What kind of packet is this ? */#if ENABLE_DEBUG else if (header->type <= ICMP_MAX_TYPE) { if (svz_icmp_request[header->type]) svz_log (LOG_DEBUG, "icmp: %s received\n", svz_icmp_request[header->type]); else svz_log (LOG_DEBUG, "unsupported protocol 0x%02X received\n", header->type); return ICMP_ERROR; }#endif /* ENABLE_DEBUG */ if (header->type == sock->itype) { if (header->code == ICMP_SERVEEZ_CONNECT && sock->flags & SOCK_FLAG_LISTENING) { svz_log (LOG_NOTICE, "icmp: accepting connection\n"); } else if (header->code == ICMP_SERVEEZ_CLOSE) { svz_log (LOG_NOTICE, "icmp: closing connection\n"); return ICMP_DISCONNECT; } return (length + ICMP_HEADER_SIZE); }#if ENABLE_DEBUG else { svz_log (LOG_DEBUG, "unsupported protocol 0x%02X received\n", header->type); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -