Page:
ex__network__ssl__hardened_8c
Pages
Examples
Files
Home
Module AABB3D
Module ACCEPT_POOL
Module ALLEGRO4
Module ALLEGRO5
Module ANIM_LIB
Module ASTAR
Module ATLAS_LIB
Module AVRO
Module CLOCK_SYNC
Module COMMONS
Module CONFIGFILE
Module CYPHER_BASE64
Module CYPHER_VIGENERE
Module DEAD_RECKONING
Module ENUMS
Module EXCEPTIONS
Module GAME_ENV
Module GIT
Module GUI
Module HASH_TABLE
Module ISOMETRIC_ENGINE
Module LIST
Module LOG
Module LOGNODUP
Module LZ4
Module NETWORKING
Module NETWORK_MSG
Module N_COOKIES
Module N_DIFF
Module N_DIGEST
Module N_DISK_CACHE
Module N_DNS
Module N_ECC
Module N_ENTROPY
Module N_FILES
Module N_FLUIDS
Module N_GUI_COLOR
Module N_GUI_COLORWHEEL
Module N_GUI_CURVE
Module N_GUI_GRID
Module N_GUI_POPUP
Module N_HEX
Module N_HTTP3
Module N_HTTP_COOKIE
Module N_HTTP_FORM
Module N_HTTP_MIME
Module N_HTTP_REQ
Module N_HTTP_RESP
Module N_HTTP_ROUTER
Module N_HTTP_SERVER
Module N_ICC
Module N_JSON
Module N_KAFKA
Module N_LINALG
Module N_MODULE
Module N_OPENSSL_COMPAT
Module N_PRETTY
Module N_PTH
Module N_QUERY
Module N_RANDOM
Module N_SHA256
Module N_STR
Module N_TIFF
Module N_TIME
Module N_USER
Module N_X509
Module N_ZIP
Module PARTICLES
Module PCRE
Module PHYSICS
Module SIGNALS
Module STACK
Module THREADS
Module TRAJECTORY
Module TREE
Module ZLIB
Modules
Pages
Struct A4_BMP
Struct A4_TIMER
Struct AABB3D
Struct ANIM_DATA
Struct ANIM_FRAME
Struct ANIM_GFX
Struct ANIM_LIB
Struct ASTAR_BOX
Struct ASTAR_CELL
Struct ASTAR_GRID
Struct ASTAR_HEAP
Struct ASTAR_HEAP_NODE
Struct ASTAR_NODE
Struct ASTAR_PATH
Struct AVRO_FIELD
Struct AVRO_READER
Struct AVRO_SCHEMA
Struct BITMAP
Struct CALLBACK_DATA
Struct CA_CTX
Struct CLIENT_JOB
Struct CLIENT_STATE
Struct CONFIG_FILE
Struct CONFIG_FILE_SECTION
Struct CYPHER_PARAM
Struct DATA
Struct DEMO_PANEL
Struct DICTIONARY_DEFINITION
Struct DICTIONARY_ENTRY
Struct DIFF_OUT
Struct DIFF_TEXT
Struct DRAW_STATE
Struct DR_ENTITY
Struct DR_STATE
Struct DR_VEC3
Struct ExceptionContextList
Struct FONT
Struct GAME_ENV
Struct H2BUF
Struct H2_DYN_ENTRY
Struct H2_STREAM
Struct HASH_NODE
Struct HASH_TABLE
Struct ISO_DRAW_ENTRY
Struct ISO_MAP
Struct ISO_PROJECTION
Struct ISO_TILE_SEGMENT
Struct ISO_TILE_SEGMENTS
Struct ISO_VISIBLE_EDGES
Struct JS_STATE
Struct LEX_ITEM
Struct LIST
Struct LIST_NODE
Struct LOG_LEVELS
Struct LexMenu
Struct MEMBER
Struct MIDI
Struct NESTED
Struct NETWORK
Struct NETWORK_HTTP_INFO
Struct NETWORK_POOL
Struct NETWORK_SSL_THREAD_PARAMS
Struct NETW_ACCEPT_POOL
Struct NETW_ACCEPT_POOL_STATS
Struct NETW_MSG
Struct NETW_SNI_ARG
Struct NODE_DATA
Struct N_ATLAS
Struct N_ATLAS_PAGE
Struct N_CLOCK_SYNC
Struct N_COOKIE
Struct N_COOKIE_JAR
Struct N_DIFF_LINE
Struct N_DIFF_RESULT
Struct N_DISK_CACHE
Struct N_ENTROPY_BIT
Struct N_ENTROPY_POS
Struct N_FILE_INFO
Struct N_FLUID
Struct N_FLUID_THREAD_PARAMS
Struct N_FORM_FIELD
Struct N_GIT_COMMIT_INFO
Struct N_GIT_REMOTE_AUTH
Struct N_GIT_REPO
Struct N_GIT_STATUS_ENTRY
Struct N_GUI_BUTTON_DATA
Struct N_GUI_CHECKBOX_DATA
Struct N_GUI_COLOR_PICKER
Struct N_GUI_COMBOBOX_DATA
Struct N_GUI_CTX
Struct N_GUI_CUSTOM_DATA
Struct N_GUI_DATAGRID_COL
Struct N_GUI_DATAGRID_DATA
Struct N_GUI_DROPMENU_DATA
Struct N_GUI_DROPMENU_ENTRY
Struct N_GUI_GRID_CALLBACKS
Struct N_GUI_HEXVIEW_DATA
Struct N_GUI_IMAGE_DATA
Struct N_GUI_KVTABLE
Struct N_GUI_KV_CONTENT
Struct N_GUI_KV_ROW
Struct N_GUI_LABEL_DATA
Struct N_GUI_LISTBOX_DATA
Struct N_GUI_LISTITEM
Struct N_GUI_MARKDOWNVIEW_DATA
Struct N_GUI_MD_FONTS
Struct N_GUI_MD_STYLE
Struct N_GUI_MEAS_ENTRY
Struct N_GUI_MOUSE_EVENT
Struct N_GUI_PENDING_GEOM
Struct N_GUI_PENDING_WIDGET
Struct N_GUI_POPUP
Struct N_GUI_PROGRESSBAR_DATA
Struct N_GUI_RADIOLIST_DATA
Struct N_GUI_SB_TRACK
Struct N_GUI_SCROLLBAR_DATA
Struct N_GUI_SECTION
Struct N_GUI_SECTIONLIST
Struct N_GUI_SLIDER_DATA
Struct N_GUI_SPLITPANE_DATA
Struct N_GUI_STYLE
Struct N_GUI_SUGGEST_SINK
Struct N_GUI_SYNTAXVIEW_DATA
Struct N_GUI_TAB_PANEL
Struct N_GUI_TB_BUTTONS
Struct N_GUI_TEXTAREA_DATA
Struct N_GUI_TEXT_DIMS
Struct N_GUI_THEME
Struct N_GUI_TREE
Struct N_GUI_TREE_NODE
Struct N_GUI_TREE_STATE
Struct N_GUI_WIDGET
Struct N_GUI_WINDOW
Struct N_H2_FRAME
Struct N_H2_HEADER
Struct N_H2_HPACK
Struct N_H2_REQUEST
Struct N_H2_SERVER
Struct N_H2_SETTING
Struct N_HTML_ATTR_
Struct N_HTML_FORM
Struct N_HTML_TAG_
Struct N_HTTP3_RESPONSE
Struct N_HTTP_FIELD
Struct N_HTTP_FORM
Struct N_HTTP_FORM_MULTIPART
Struct N_HTTP_FORM_PART
Struct N_HTTP_MULTIPART_PART
Struct N_HTTP_REQUEST
Struct N_HTTP_RESP
Struct N_HTTP_RESPONSE
Struct N_HTTP_SERVER
Struct N_HTTP_SERVER_CONFIG
Struct N_HTTP_SERVER_REQUEST
Struct N_HTTP_SERVER_STATS
Struct N_HTTP_SET_COOKIE
Struct N_HTTP_STREAM
Struct N_ISO_CAMERA
Struct N_ISO_OBJECT
Struct N_KAFKA
Struct N_KAFKA_EVENT
Struct N_MOCK_SERVER
Struct N_MODULE
Struct N_PARALLEL_SLICE
Struct N_PARALLEL_TEAM
Struct N_PARALLEL_WORKER
Struct N_PCRE
Struct N_PROXY_CFG
Struct N_PTH
Struct N_PTH_TENSOR
Struct N_QUERY
Struct N_ROUTE
Struct N_ROUTER
Struct N_ROUTE_MATCH
Struct N_SHA256
Struct N_SOCKET
Struct N_SPAWN_PIPE
Struct N_SSE_CONN
Struct N_SSE_EVENT
Struct N_STR
Struct N_TIFF
Struct N_TIFF_ENTRY
Struct N_TIME
Struct N_URL
Struct N_URL_PARAM
Struct N_USER
Struct N_USERLIST
Struct N_WS_CONN
Struct N_WS_FRAME
Struct N_WS_MESSAGE
Struct N_ZIP_MEMBER
Struct OCTREE
Struct OCTREE_NODE
Struct PARSER
Struct PARTICLE
Struct PARTICLE_EMITTER
Struct PARTICLE_SYSTEM
Struct PEER
Struct PHYSICS
Struct PK_OBJ
Struct PK_VM
Struct POINT2D
Struct POINT3D
Struct PRETTY_OUT
Struct QNODE
Struct QUADTREE
Struct QUADTREE_NODE
Struct REC
Struct RGB
Struct SAMPLE
Struct SEEN
Struct SHARER
Struct SRV
Struct SRV_ARG
Struct STACK
Struct STACK_ITEM
Struct SYNTAX_RUN
Struct THREAD_POOL
Struct THREAD_POOL_NODE
Struct THREAD_WAITING_PROC
Struct TRAJECTORY
Struct TRAJECTORY_POINT
Struct TREE
Struct TREE_NODE
Struct TS_LOG
Struct WAYPOINT3D
Struct WORKER_ARG
Struct ZIP_SINK
Struct _N_DC_ENTRY
Struct _N_DC_GROUP_ENTRY
Struct _N_GUI_COLORWHEEL
Struct _N_GUI_COLORWHEEL_BLOCK
Struct _N_GUI_COLORWHEEL_MOUSE
Struct _N_GUI_CURVE
Struct _N_GUI_CURVE_BLOCK
Struct _N_GUI_CURVE_MOUSE
Struct _N_GUI_GRID
Struct _N_GUI_POPUP_ENTRY
Struct _N_GUI_POPUP_LEVEL
Struct _N_GUI_SB_SKIN
Struct _N_GUI_TA_STEP
Struct _N_GUI_THUMB
Struct _N_GUI_WRAP_ACC
Struct _compiled
Struct _conn
Struct _ip_slot
Struct _mp_param
Struct _n_civil
Struct _seg
Struct client
Struct collector
Struct date_vector
Struct md_atom
Struct md_cells
Struct md_hit
Struct md_line_ctx
Struct mline
Struct n_http_req_header
Struct n_http_req_limits
Struct n_http_request
Struct n_markdown_block
Struct n_markdown_doc
Struct n_markdown_inline
Struct n_markdown_span
Struct n_reactor_stats
Struct n_url_safe
Struct n_url_safe_head
Struct n_wrap_item
Struct producer_state
Struct rects
Struct reply
Struct runner
Struct sink
Struct tbuf
Struct wrap_hit
Struct wrap_span
Structures
Union COORD_VALUE
Union HASH_DATA
Union NODE_DATA_TYPES
Union STACK_DATA
dir_310dcdd4703e877a6b99d5dc3fc54d27
dir_68267d1309a1af8e8297ef4c3efbcdba
dir_d28a4824dc47e487b107a5db32ef43c4
dir_d44c64559bbebec7f509842c48db8b23
ex__accept__pool__client_8c
ex__accept__pool__server_8c
ex__allegro__4_8c
ex__atlas_8c
ex__avro_8c
ex__base64_8c
ex__bind__exclusive_8c
ex__clipboard_8c
ex__clock__sync_8c
ex__common_8c
ex__configfile_8c
ex__cookies_8c
ex__crypto_8c
ex__diff_8c
ex__digest_8c
ex__disk__cache_8c
ex__dns_8c
ex__ecc_8c
ex__entropy_8c
ex__exceptions_8c
ex__file_8c
ex__file__copy_8c
ex__fluid_8c
ex__fluid__config_8c
ex__fluid__config_8h
ex__git_8c
ex__gui_8c
ex__gui__bench_8c
ex__gui__button__keys_8c
ex__gui__checkbox__label_8c
ex__gui__checkbox__release_8c
ex__gui__color__picker_8c
ex__gui__colorwheel_8c
ex__gui__combobox__items_8c
ex__gui__combobox__wheel_8c
ex__gui__cursor_8c
ex__gui__curve_8c
ex__gui__custom_8c
ex__gui__custom__mouse_8c
ex__gui__datagrid_8c
ex__gui__datagrid__keys_8c
ex__gui__datagrid__sort_8c
ex__gui__detach_8c
ex__gui__dictionary_8c
ex__gui__display__fallback_8c
ex__gui__double__click_8c
ex__gui__dropmenu_8c
ex__gui__frameless__drag_8c
ex__gui__global__scroll_8c
ex__gui__glyph_8c
ex__gui__grid_8c
ex__gui__hexview_8c
ex__gui__hover_8c
ex__gui__isometric_8c
ex__gui__kvtable_8c
ex__gui__label__fits_8c
ex__gui__label__lines_8c
ex__gui__layout__persist_8c
ex__gui__listbox_8c
ex__gui__md_8c
ex__gui__multiwin_8c
ex__gui__network_8c
ex__gui__particles_8c
ex__gui__placeholder_8c
ex__gui__popup_8c
ex__gui__progressbar_8c
ex__gui__reentrant_8c
ex__gui__round_8c
ex__gui__sectionlist_8c
ex__gui__slider__default_8c
ex__gui__slider__handle_8c
ex__gui__slider__step_8c
ex__gui__splitpane_8c
ex__gui__suggest_8c
ex__gui__syntaxview_8c
ex__gui__text__shorten_8c
ex__gui__textarea__selection_8c
ex__gui__tooltip_8c
ex__gui__tree__lazy_8c
ex__gui__tree__order_8c
ex__gui__tree__state_8c
ex__gui__window__rect_8c
ex__gui__zorder_8c
ex__hash_8c
ex__hex_8c
ex__html_8c
ex__http2_8c
ex__http2__server_8c
ex__http3_8c
ex__http__cookie_8c
ex__http__form_8c
ex__http__mime_8c
ex__http__req_8c
ex__http__response_8c
ex__http__router_8c
ex__http__server_8c
ex__icc_8c
ex__iso__astar_8c
ex__json_8c
ex__kafka_8c
ex__linalg_8c
ex__list_8c
ex__log_8c
ex__markdown_8c
ex__module_8c
ex__monolith_8c
ex__network_8c
ex__network_8h
ex__network__accept_8c
ex__network__alpn_8c
ex__network__connect__abort_8c
ex__network__mock_8c
ex__network__proxy_8c
ex__network__reactor_8c
ex__network__sni_8c
ex__network__sse_8c
ex__network__ssl_8c
ex__network__ssl__hardened_8c
ex__network__ssl__hostname_8c
ex__network__ssl__nonblock_8c
ex__network__tls__defaults_8c
ex__network__ws_8c
ex__network__ws__limits_8c
ex__nstr_8c
ex__parallel__for_8c
ex__parallel__team_8c
ex__pcre_8c
ex__pretty_8c
ex__pth_8c
ex__query_8c
ex__random_8c
ex__sha256_8c
ex__signals_8c
ex__spawn_8c
ex__ssrf_8c
ex__stack_8c
ex__thread__pool__discard_8c
ex__thread__pool__wait_8c
ex__threads_8c
ex__tiff_8c
ex__time__formats_8c
ex__trajectory_8c
ex__trees_8c
ex__url_8c
ex__url__safe_8c
ex__wrap_8c
ex__x509_8c
ex__zip_8c
ex__zlib_8c
ex_accept_pool_client_8c example
ex_accept_pool_server_8c example
ex_allegro_4_8c example
ex_atlas_8c example
ex_base64_8c example
ex_clock_sync_8c example
ex_common_8c example
ex_configfile_8c example
ex_cookies_8c example
ex_crypto_8c example
ex_diff_8c example
ex_digest_8c example
ex_disk_cache_8c example
ex_dns_8c example
ex_ecc_8c example
ex_entropy_8c example
ex_exceptions_8c example
ex_file_8c example
ex_file_copy_8c example
ex_fluid_8c example
ex_fluid_config_8c example
ex_fluid_config_8h example
ex_git_8c example
ex_gui_8c example
ex_gui_bench_8c example
ex_gui_button_keys_8c example
ex_gui_checkbox_label_8c example
ex_gui_checkbox_release_8c example
ex_gui_color_picker_8c example
ex_gui_colorwheel_8c example
ex_gui_combobox_items_8c example
ex_gui_combobox_wheel_8c example
ex_gui_cursor_8c example
ex_gui_curve_8c example
ex_gui_custom_8c example
ex_gui_custom_mouse_8c example
ex_gui_datagrid_8c example
ex_gui_datagrid_keys_8c example
ex_gui_datagrid_sort_8c example
ex_gui_detach_8c example
ex_gui_dictionary_8c example
ex_gui_display_fallback_8c example
ex_gui_double_click_8c example
ex_gui_dropmenu_8c example
ex_gui_frameless_drag_8c example
ex_gui_global_scroll_8c example
ex_gui_glyph_8c example
ex_gui_grid_8c example
ex_gui_hexview_8c example
ex_gui_hover_8c example
ex_gui_isometric_8c example
ex_gui_kvtable_8c example
ex_gui_label_fits_8c example
ex_gui_label_lines_8c example
ex_gui_layout_persist_8c example
ex_gui_listbox_8c example
ex_gui_md_8c example
ex_gui_multiwin_8c example
ex_gui_network_8c example
ex_gui_particles_8c example
ex_gui_placeholder_8c example
ex_gui_popup_8c example
ex_gui_progressbar_8c example
ex_gui_reentrant_8c example
ex_gui_round_8c example
ex_gui_sectionlist_8c example
ex_gui_slider_default_8c example
ex_gui_slider_handle_8c example
ex_gui_slider_step_8c example
ex_gui_splitpane_8c example
ex_gui_suggest_8c example
ex_gui_syntaxview_8c example
ex_gui_text_shorten_8c example
ex_gui_textarea_selection_8c example
ex_gui_tooltip_8c example
ex_gui_tree_lazy_8c example
ex_gui_tree_order_8c example
ex_gui_tree_state_8c example
ex_gui_window_rect_8c example
ex_gui_zorder_8c example
ex_hash_8c example
ex_hex_8c example
ex_html_8c example
ex_http2_8c example
ex_http2_server_8c example
ex_http_cookie_8c example
ex_http_form_8c example
ex_http_mime_8c example
ex_http_req_8c example
ex_http_response_8c example
ex_http_router_8c example
ex_http_server_8c example
ex_icc_8c example
ex_iso_astar_8c example
ex_json_8c example
ex_kafka_8c example
ex_linalg_8c example
ex_list_8c example
ex_log_8c example
ex_markdown_8c example
ex_module_8c example
ex_monolith_8c example
ex_network_8c example
ex_network_8h example
ex_network_accept_8c example
ex_network_alpn_8c example
ex_network_connect_abort_8c example
ex_network_mock_8c example
ex_network_proxy_8c example
ex_network_reactor_8c example
ex_network_sni_8c example
ex_network_sse_8c example
ex_network_ssl_8c example
ex_network_ssl_hardened_8c example
ex_network_ssl_hostname_8c example
ex_network_ssl_nonblock_8c example
ex_network_tls_defaults_8c example
ex_network_ws_8c example
ex_network_ws_limits_8c example
ex_nstr_8c example
ex_parallel_for_8c example
ex_parallel_team_8c example
ex_pcre_8c example
ex_pretty_8c example
ex_pth_8c example
ex_query_8c example
ex_random_8c example
ex_sha256_8c example
ex_signals_8c example
ex_spawn_8c example
ex_ssrf_8c example
ex_stack_8c example
ex_threads_8c example
ex_tiff_8c example
ex_time_formats_8c example
ex_trajectory_8c example
ex_trees_8c example
ex_url_8c example
ex_url_safe_8c example
ex_wrap_8c example
ex_x509_8c example
ex_zip_8c example
ex_zlib_8c example
mainpage_8dox
n__3d_8c
n__3d_8h
n__aabb_8c
n__aabb_8h
n__allegro5_8c
n__allegro5_8h
n__allegro__4_8c
n__allegro__4_8h
n__anim_8c
n__anim_8h
n__astar_8c
n__astar_8h
n__atlas_8c
n__atlas_8h
n__avro_8c
n__avro_8h
n__base64_8c
n__base64_8h
n__clipboard_8c
n__clipboard_8h
n__clock__sync_8c
n__clock__sync_8h
n__common_8c
n__common_8h
n__config__file_8c
n__config__file_8h
n__cookies_8c
n__cookies_8h
n__crypto_8c
n__crypto_8h
n__dead__reckoning_8c
n__dead__reckoning_8h
n__diff_8c
n__diff_8h
n__digest_8c
n__digest_8h
n__disk__cache_8c
n__disk__cache_8h
n__dns_8c
n__dns_8h
n__ecc_8c
n__ecc_8h
n__entropy_8c
n__entropy_8h
n__enum_8h
n__exceptions_8c
n__exceptions_8h
n__files_8c
n__files_8h
n__fluids_8c
n__fluids_8h
n__games_8c
n__games_8h
n__git_8c
n__git_8h
n__gui_8c
n__gui_8h
n__gui__color_8c
n__gui__color_8h
n__gui__colorwheel_8c
n__gui__colorwheel_8h
n__gui__curve_8c
n__gui__curve_8h
n__gui__grid_8c
n__gui__grid_8h
n__gui__md_8c
n__gui__md_8h
n__gui__popup_8c
n__gui__popup_8h
n__hash_8c
n__hash_8h
n__hex_8c
n__hex_8h
n__html_8c
n__html_8h
n__http2_8c
n__http2_8h
n__http2__server_8c
n__http2__server_8h
n__http3_8c
n__http3_8h
n__http__cookie_8c
n__http__cookie_8h
n__http__form_8c
n__http__form_8h
n__http__mime_8c
n__http__mime_8h
n__http__req_8c
n__http__req_8h
n__http__response_8c
n__http__response_8h
n__http__router_8c
n__http__router_8h
n__http__server_8c
n__http__server_8h
n__icc_8c
n__icc_8h
n__iso__engine_8c
n__iso__engine_8h
n__json_8c
n__json_8h
n__kafka_8c
n__kafka_8h
n__linalg_8c
n__linalg_8h
n__list_8c
n__list_8h
n__log_8c
n__log_8h
n__lz4_8c
n__lz4_8h
n__markdown_8c
n__markdown_8h
n__module_8c
n__module_8h
n__network_8c
n__network_8h
n__network__accept__pool_8c
n__network__accept__pool_8h
n__network__msg_8c
n__network__msg_8h
n__nodup__log_8c
n__nodup__log_8h
n__openssl__compat_8h
n__particles_8c
n__particles_8h
n__pcre_8c
n__pcre_8h
n__pretty_8c
n__pretty_8h
n__pth_8c
n__pth_8h
n__query_8c
n__query_8h
n__random_8c
n__random_8h
n__reactor_8c
n__reactor_8h
n__sha256_8c
n__sha256_8h
n__signals_8c
n__signals_8h
n__ssrf_8c
n__ssrf_8h
n__stack_8c
n__stack_8h
n__str_8c
n__str_8h
n__thread__pool_8c
n__thread__pool_8h
n__tiff_8c
n__tiff_8h
n__time_8c
n__time_8h
n__trajectory_8c
n__trajectory_8h
n__trees_8c
n__trees_8h
n__url__safe_8c
n__url__safe_8h
n__user_8c
n__user_8h
n__windows_8h
n__wrap_8c
n__wrap_8h
n__x509_8c
n__x509_8h
n__zip_8c
n__zip_8h
n__zlib_8c
n__zlib_8h
nilorea_8h
No results
7
ex__network__ssl__hardened_8c
gullradriel edited this page 2026-10-29 20:54:40 +01:00
Table of Contents
- examples/ex_network_ssl_hardened.c
- Structures
- Functions
- Attributes
- Defines
- Functions Documentation
- function validate_path
- function usage
- function ssl_network_thread
- function ssl_harden_context
- function set_socket_timeout
- function process_args
- function main
- function handle_request
- function build_secure_response
- function action_on_sig
- Attributes Documentation
- variable ssl_verify
- variable server
- variable routes
- variable root_dir
- variable port
- variable netw
- variable max_http_request_size
- variable max_connections
- variable killed_by_signal
- variable ip_version
- variable done
- variable cert
- variable ca_file
- variable addr
- variable accept_timeout
- Macros Documentation
- Source code
examples/ex_network_ssl_hardened.c
Structures
| Name | |
|---|---|
| struct | NETWORK_SSL_THREAD_PARAMS structure of a NETWORK_SSL_THREAD_PARAMS |
Functions
| Name | |
|---|---|
| int | validate_path(const char * requested_path, const char * root, char * resolved, size_t resolved_size) Validate that a resolved path stays within the document root. |
| void | usage(void ) |
| void * | ssl_network_thread(void * params) |
| int | ssl_harden_context(NETWORK * ssl_netw) Harden the SSL context with modern security settings. |
| int | set_socket_timeout(SOCKET sock, int timeout_seconds) Set socket read/write timeout to prevent slow-loris attacks. |
| void | process_args(int argc_nb, char ** argv_ptr, char ** addr_ptr, char ** port_ptr, char ** key_ptr, char ** cert_ptr, char ** ca_file_ptr, int * ssl_verify_ptr, LIST * routes_ptr, int * ip_version_ptr, int * max_http_request_size_ptr, char ** root_dir_ptr) |
| int | main(int argc, char * argv[]) |
| void | handle_request(NETWORK * netw_ptr, LIST * routes_ptr) |
| int | build_secure_response(N_STR ** response, int status_code, const char * content_type, char * extra_headers, N_STR * body) |
| void | action_on_sig(int recvd_signal) |
Attributes
| Name | |
|---|---|
| int | ssl_verify |
| NETWORK * | server |
| LIST * | routes |
| char * | root_dir |
| char * | port |
| NETWORK * | netw Network for server mode, accepting incomming. |
| int | max_http_request_size |
| int | max_connections |
| volatile sig_atomic_t | killed_by_signal |
| int | ip_version |
| volatile sig_atomic_t | done |
| char * | cert |
| char * | ca_file |
| char * | addr |
| int | accept_timeout |
Defines
| Name | |
|---|---|
| SECURITY_HEADERS Network for managing connections. |
|
| MAX_HTTP_REQUEST_SIZE_LIMIT | |
| CONNECTION_TIMEOUT_SECONDS |
Functions Documentation
function validate_path
int validate_path(
const char * requested_path,
const char * root,
char * resolved,
size_t resolved_size
)
Validate that a resolved path stays within the document root.
Parameters:
- requested_path the filesystem path constructed from the URL
- root the document root directory
- resolved output buffer for the validated absolute path
- resolved_size size of the output buffer
Return: TRUE if the path is safe, FALSE if it escapes the root
Resolves the requested path using realpath() and checks that it starts with the resolved root directory, preventing path traversal attacks (e.g., GET /../../etc/passwd).
function usage
void usage(
void
)
function ssl_network_thread
void * ssl_network_thread(
void * params
)
function ssl_harden_context
int ssl_harden_context(
NETWORK * ssl_netw
)
Harden the SSL context with modern security settings.
Parameters:
- ssl_netw the network whose SSL_CTX to harden
Return: TRUE on success, FALSE on failure
Applied after netw_set_crypto/netw_set_crypto_chain to tighten TLS configuration:
- Enforce TLS 1.2 minimum
- Restrict cipher suites to strong AEAD ciphers with forward secrecy
- Disable compression (CRIME attack)
- Server cipher preference
- Disable session tickets for forward secrecy
- Configure ECDH curves
function set_socket_timeout
int set_socket_timeout(
SOCKET sock,
int timeout_seconds
)
Set socket read/write timeout to prevent slow-loris attacks.
Parameters:
- sock the socket file descriptor
- timeout_seconds timeout in seconds
Return: TRUE on success, FALSE on failure
function process_args
void process_args(
int argc_nb,
char ** argv_ptr,
char ** addr_ptr,
char ** port_ptr,
char ** key_ptr,
char ** cert_ptr,
char ** ca_file_ptr,
int * ssl_verify_ptr,
LIST * routes_ptr,
int * ip_version_ptr,
int * max_http_request_size_ptr,
char ** root_dir_ptr
)
function main
int main(
int argc,
char * argv[]
)
function handle_request
void handle_request(
NETWORK * netw_ptr,
LIST * routes_ptr
)
function build_secure_response
int build_secure_response(
N_STR ** response,
int status_code,
const char * content_type,
char * extra_headers,
N_STR * body
)
function action_on_sig
void action_on_sig(
int recvd_signal
)
Attributes Documentation
variable ssl_verify
int ssl_verify = 0;
variable server
NETWORK * server = NULL;
variable routes
LIST * routes = NULL;
variable root_dir
char * root_dir = NULL;
variable port
char * port = NULL;
variable netw
NETWORK * netw = NULL;
Network for server mode, accepting incomming.
variable max_http_request_size
int max_http_request_size = 16384;
variable max_connections
int max_connections = 0;
variable killed_by_signal
volatile sig_atomic_t killed_by_signal = 0;
variable ip_version
int ip_version = 0;
variable done
volatile sig_atomic_t done = 0;
variable cert
char * cert = NULL;
variable ca_file
char * ca_file = NULL;
variable addr
char * addr = NULL;
variable accept_timeout
int accept_timeout = 30;
Macros Documentation
define SECURITY_HEADERS
#define SECURITY_HEADERS "Strict-Transport-Security: max-age=31536000\r\n" \
"X-Content-Type-Options: nosniff\r\n" \
"X-Frame-Options: DENY\r\n" \
"Content-Security-Policy: default-src 'self'\r\n" \
"Referrer-Policy: strict-origin-when-cross-origin\r\n" \
"Permissions-Policy: geolocation=(), camera=(), microphone=()\r\n"
Network for managing connections.
security headers appended to every response
define MAX_HTTP_REQUEST_SIZE_LIMIT
#define MAX_HTTP_REQUEST_SIZE_LIMIT 1048576
define CONNECTION_TIMEOUT_SECONDS
#define CONNECTION_TIMEOUT_SECONDS 10
Source code
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nilorea/n_list.h"
#include "nilorea/n_str.h"
#include "nilorea/n_log.h"
#include "nilorea/n_network.h"
#include "nilorea/n_thread_pool.h"
#include "nilorea/n_signals.h"
#ifdef __windows__
#define realpath(rel, abs) _fullpath(abs, rel, MAX_PATH)
#endif
char* port = NULL;
char* addr = NULL;
char* key = NULL;
char* cert = NULL;
char* ca_file = NULL;
char* root_dir = NULL;
LIST* routes = NULL;
int ip_version = NETWORK_IPALL;
int max_http_request_size = 16384;
#define MAX_HTTP_REQUEST_SIZE_LIMIT 1048576
#define CONNECTION_TIMEOUT_SECONDS 10
int ssl_verify = 0;
int max_connections = 0; /* 0 = unlimited */
/* Seconds to wait for a connection before giving up, 0 waits forever.
* Without it a server whose client never showed up sat in accept()
* until the test harness killed it, reported as a bare exit 124. */
int accept_timeout = 30;
volatile sig_atomic_t done = 0;
/* set by the SIGTERM handler so the exit status still reports the kill */
volatile sig_atomic_t killed_by_signal = 0;
NETWORK *server = NULL,
*netw = NULL;
#define SECURITY_HEADERS \
"Strict-Transport-Security: max-age=31536000\r\n" \
"X-Content-Type-Options: nosniff\r\n" \
"X-Frame-Options: DENY\r\n" \
"Content-Security-Policy: default-src 'self'\r\n" \
"Referrer-Policy: strict-origin-when-cross-origin\r\n" \
"Permissions-Policy: geolocation=(), camera=(), microphone=()\r\n"
void usage(void) {
fprintf(stderr,
" -p 'port' : set the https server port\n"
" -k 'key file' : SSL key file path\n"
" -c 'cert file' : SSL certificate file path\n"
" -A 'CA file' : optional, CA certificate file for chain verification\n"
" -e : optional, enable SSL peer certificate verification\n"
" -a 'address name/ip' : optional, specify where to bind interface\n"
" -i 'ipmode' : optional, force 'ipv4' or 'ipv6', default supports both\n"
" -s 'size' : optional, maximum http request size (default: %d, max: %d)\n"
" -n 'count' : optional, exit after count connections (0 = unlimited, default)\n"
" -w 'seconds' : optional, give up after seconds without a connection (0 = wait forever, default: 30)\n"
" -d 'html root' : optional, specify a different http root dir (default: ./DATAS/)\n"
" -v : version\n"
" -h : help\n"
" -V 'log level' : optional, set the log level (default: LOG_ERR)\n",
max_http_request_size, MAX_HTTP_REQUEST_SIZE_LIMIT);
}
void process_args(int argc_nb, char** argv_ptr, char** addr_ptr, char** port_ptr, char** key_ptr, char** cert_ptr, char** ca_file_ptr, int* ssl_verify_ptr, LIST* routes_ptr, int* ip_version_ptr, int* max_http_request_size_ptr, char** root_dir_ptr) {
int getoptret = 0,
log_level = LOG_ERR; /* default log level */
if (argc_nb == 1) {
fprintf(stderr, "No arguments given, help:\n");
usage();
exit(1);
}
while ((getoptret = getopt(argc_nb, argv_ptr, "hven:s:V:p:i:a:r:k:c:s:d:A:w:")) != EOF) {
switch (getoptret) {
case 'n':
max_connections = atoi(optarg);
break;
case 'w':
accept_timeout = atoi(optarg);
break;
case 'i':
if (!strcmp("v4", optarg)) {
(*ip_version_ptr) = NETWORK_IPV4;
n_log(LOG_NOTICE, "IPV4 selected");
} else if (!strcmp("v6", optarg)) {
(*ip_version_ptr) = NETWORK_IPV6;
n_log(LOG_NOTICE, "IPV6 selected");
} else {
n_log(LOG_NOTICE, "IPV4/6 selected");
}
break;
case 'v':
fprintf(stderr, "Date de compilation : %s a %s.\n", __DATE__, __TIME__);
exit(1);
case 'V':
if (!strncmp("LOG_NULL", optarg, 8)) {
log_level = LOG_NULL;
} else {
if (!strncmp("LOG_NOTICE", optarg, 10)) {
log_level = LOG_NOTICE;
} else {
if (!strncmp("LOG_INFO", optarg, 8)) {
log_level = LOG_INFO;
} else {
if (!strncmp("LOG_ERR", optarg, 7)) {
log_level = LOG_ERR;
} else {
if (!strncmp("LOG_DEBUG", optarg, 9)) {
log_level = LOG_DEBUG;
} else {
fprintf(stderr, "%s n'est pas un niveau de log valide.\n", optarg);
exit(-1);
}
}
}
}
}
break;
case 'e':
(*ssl_verify_ptr) = 1;
break;
case 'p':
(*port_ptr) = strdup(optarg);
break;
case 'r':
list_push(routes_ptr, strdup(optarg), &free);
break;
case 'a':
(*addr_ptr) = strdup(optarg);
break;
case 'k':
(*key_ptr) = strdup(optarg);
break;
case 'c':
(*cert_ptr) = strdup(optarg);
break;
case 'A':
(*ca_file_ptr) = strdup(optarg);
break;
case 's': {
int val = atoi(optarg);
if (val <= 0 || val > MAX_HTTP_REQUEST_SIZE_LIMIT) {
fprintf(stderr, "Invalid max http request size: %s (must be 1-%d)\n", optarg, MAX_HTTP_REQUEST_SIZE_LIMIT);
exit(1);
}
(*max_http_request_size_ptr) = val;
break;
}
case 'd':
(*root_dir_ptr) = strdup(optarg);
break;
default:
case '?': {
if (optopt == 'd') {
fprintf(stderr, "\n Missing html root directory\n");
}
if (optopt == 's') {
fprintf(stderr, "\n Missing max http size string\n");
}
if (optopt == 'k') {
fprintf(stderr, "\n Missing key file string\n");
}
if (optopt == 'c') {
fprintf(stderr, "\n Missing certificate file string\n");
}
if (optopt == 'A') {
fprintf(stderr, "\n Missing CA file string\n");
}
if (optopt == 'r') {
fprintf(stderr, "\n Missing route string\n");
}
if (optopt == 'a') {
fprintf(stderr, "\n Missing binding host/addr string\n");
}
if (optopt == 'i') {
fprintf(stderr, "\n Missing ip version (v4 or v6) string \n");
} else if (optopt == 'V') {
fprintf(stderr, "\n Missing log level string\n");
} else if (optopt == 'p') {
fprintf(stderr, "\n Missing port\n");
} else if (optopt != 's') {
fprintf(stderr, "\n Unknow missing option %c\n", optopt);
}
usage();
exit(1);
}
case 'h': {
usage();
exit(1);
}
}
}
set_log_level(log_level);
} /* void process_args( ... ) */
int ssl_harden_context(NETWORK* ssl_netw) {
__n_assert(ssl_netw, return FALSE);
__n_assert(ssl_netw->ctx, return FALSE);
/* Enforce TLS 1.2 minimum */
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
if (!SSL_CTX_set_min_proto_version(ssl_netw->ctx, TLS1_2_VERSION)) {
n_log(LOG_ERR, "Failed to set minimum TLS version to 1.2");
return FALSE;
}
#else
SSL_CTX_set_options(ssl_netw->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
#endif
/* Security options:
* - NO_COMPRESSION: prevents CRIME attack
* - CIPHER_SERVER_PREFERENCE: server chooses cipher order
* - NO_SESSION_RESUMPTION_ON_RENEGOTIATION: prevent renegotiation abuse
* - NO_TICKET: disable stateless session tickets for better forward secrecy
* - SINGLE_DH_USE / SINGLE_ECDH_USE: fresh keys for each handshake */
SSL_CTX_set_options(ssl_netw->ctx,
SSL_OP_NO_COMPRESSION |
SSL_OP_CIPHER_SERVER_PREFERENCE |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_NO_TICKET |
SSL_OP_SINGLE_DH_USE |
SSL_OP_SINGLE_ECDH_USE);
/* Strong cipher suites: AEAD ciphers with forward secrecy only */
const char* cipher_list = "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES:!SEED:!IDEA:!CAMELLIA";
if (!SSL_CTX_set_cipher_list(ssl_netw->ctx, cipher_list)) {
n_log(LOG_ERR, "Failed to set cipher list");
return FALSE;
}
/* TLS 1.3 cipher suites (if supported) */
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
SSL_CTX_set_ciphersuites(ssl_netw->ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
#endif
/* Configure ECDH: prefer X25519 and P-256 curves */
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
if (!SSL_CTX_set1_groups_list(ssl_netw->ctx, "X25519:P-256:P-384")) {
n_log(LOG_ERR, "Failed to set ECDH groups");
return FALSE;
}
#elif OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_ecdh_auto(ssl_netw->ctx, 1);
#endif
/* Session cache: use server-side cache with a short timeout */
SSL_CTX_set_session_cache_mode(ssl_netw->ctx, SSL_SESS_CACHE_SERVER);
SSL_CTX_set_timeout(ssl_netw->ctx, 300); /* 5 minutes */
n_log(LOG_INFO, "SSL context hardened: TLS 1.2+, strong ciphers, no compression");
return TRUE;
} /* ssl_harden_context */
int set_socket_timeout(SOCKET sock, int timeout_seconds) {
#ifndef __windows__
struct timeval tv;
tv.tv_sec = timeout_seconds;
tv.tv_usec = 0;
if (setsockopt((int)sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
n_log(LOG_ERR, "Failed to set SO_RCVTIMEO: %s", strerror(errno));
return FALSE;
}
if (setsockopt((int)sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
n_log(LOG_ERR, "Failed to set SO_SNDTIMEO: %s", strerror(errno));
return FALSE;
}
#else
DWORD tv = (DWORD)(timeout_seconds * 1000);
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) < 0) {
n_log(LOG_ERR, "Failed to set SO_RCVTIMEO");
return FALSE;
}
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv)) < 0) {
n_log(LOG_ERR, "Failed to set SO_SNDTIMEO");
return FALSE;
}
#endif
return TRUE;
}
int validate_path(const char* requested_path, const char* root, char* resolved, size_t resolved_size) {
char resolved_root[PATH_MAX] = "";
char resolved_request[PATH_MAX] = "";
/* Resolve the root directory */
if (!realpath(root, resolved_root)) {
n_log(LOG_ERR, "Cannot resolve root directory: %s (%s)", root, strerror(errno));
return FALSE;
}
/* Resolve the requested path */
if (!realpath(requested_path, resolved_request)) {
/* File doesn't exist - that's a 404, not a security issue,
* but we still need to check the parent for traversal attempts.
* If the file simply doesn't exist, return FALSE and let caller 404. */
return FALSE;
}
/* Ensure the resolved request starts with the resolved root */
size_t root_len = strlen(resolved_root);
if (strncmp(resolved_request, resolved_root, root_len) != 0) {
n_log(LOG_ERR, "Path traversal attempt blocked: %s (resolved: %s, root: %s)",
requested_path, resolved_request, resolved_root);
return FALSE;
}
/* After the root prefix, must be '/' or end of string (exact root match) */
if (resolved_request[root_len] != '/' && resolved_request[root_len] != '\0') {
n_log(LOG_ERR, "Path traversal attempt blocked (prefix match): %s", requested_path);
return FALSE;
}
strncpy(resolved, resolved_request, resolved_size - 1);
resolved[resolved_size - 1] = '\0';
return TRUE;
}
/* Exit handling */
void action_on_sig(int recvd_signal) {
(void)recvd_signal;
#ifndef __windows__
static int nb_sigterm = 0;
switch (recvd_signal) {
case (SIGABRT):
n_log(LOG_ERR, "Caught SIGABRT !");
break;
case (SIGINT):
n_log(LOG_ERR, "Caught SIGINT !");
break;
case (SIGBUS):
n_log(LOG_ERR, "Caught SIGBUS !");
break;
case (SIGFPE):
n_log(LOG_ERR, "Caught SIGFPE !");
break;
case (SIGSEGV):
n_log(LOG_ERR, "Caught SIGSEGV !");
break;
case (SIGSYS):
n_log(LOG_ERR, "Caught SIGSYS !");
break;
case (SIGTERM):
nb_sigterm++;
if (nb_sigterm >= 2) {
/* the accept loop did not pick the flag up, leave without
* unwinding: exit() would run OpenSSL's atexit cleanup and
* free() is not async-signal-safe */
_exit(-1);
}
/* no n_log() here either, just raise the flag and let the accept
* loop report it and run the normal teardown */
killed_by_signal = 1;
done = TRUE;
break;
case (SIGUSR1):
done = TRUE;
n_log(LOG_ERR, "Caught SIGUSR1 !");
break;
case (SIGUSR2):
done = TRUE;
n_log(LOG_ERR, "Caught SIGUSR2 !");
break;
case (SIGHUP):
n_log(LOG_NOTICE, "Caught SIGHUP !");
break;
default:
n_log(LOG_ERR, "Caught unknow signal %d", recvd_signal);
break;
}
#endif
} /* action_on_sig() */
/* Build a response with security headers prepended to any additional headers */
int build_secure_response(N_STR** response, int status_code, const char* content_type, char* extra_headers, N_STR* body) {
char headers[2048] = "";
snprintf(headers, sizeof(headers), "%s%s", SECURITY_HEADERS, extra_headers ? extra_headers : "");
return netw_build_http_response(response, status_code, "server", content_type, headers, body);
}
// Function to handle different URLs and return appropriate responses
void handle_request(NETWORK* netw_ptr, LIST* routes_ptr) {
__n_assert(netw_ptr, return);
__n_assert(routes_ptr, return);
bool found = 0;
char** split_results = NULL;
char* http_url = NULL;
N_STR* dynamic_request_answer = NULL;
/* the caller (ssl_network_thread) owns netw_ptr and closes it, closing it
* here too would leave it with a dangling pointer to close a second time */
__n_assert(netw_ptr->ssl, n_log(LOG_ERR, "no SSL session on socket %d", netw_ptr->link.sock); return);
/* Heap allocation instead of stack alloca to prevent stack overflow */
char* http_buffer = NULL;
Malloc(http_buffer, char, (size_t)(max_http_request_size + 1));
__n_assert(http_buffer, return);
/* Set socket timeout to prevent slow-loris attacks */
set_socket_timeout(netw_ptr->link.sock, CONNECTION_TIMEOUT_SECONDS);
// SSL_read reads up to max_http_request_size bytes (variable-length HTTP request).
// recv_ssl_data is intentionally NOT used here: it loops until the entire buffer is
// full, which would block indefinitely since HTTP requests are smaller than the buffer.
int ssl_read_ret = SSL_read(netw_ptr->ssl, http_buffer, max_http_request_size);
if (ssl_read_ret <= 0) {
int ssl_error = SSL_get_error(netw_ptr->ssl, ssl_read_ret);
if (ssl_error == SSL_ERROR_ZERO_RETURN) {
n_log(LOG_INFO, "SSL_read: peer closed the connection cleanly");
} else if (ssl_error == SSL_ERROR_SYSCALL && errno == EAGAIN) {
n_log(LOG_INFO, "SSL_read: connection timed out");
} else {
n_log(LOG_ERR, "SSL_read failed with SSL error %d", ssl_error);
}
Free(http_buffer);
return;
}
http_buffer[ssl_read_ret] = '\0';
// Extract URL from the request
char url[4096] = "";
netw_get_url_from_http_request(http_buffer, url, sizeof(url));
n_log(LOG_DEBUG, "url: %s", url);
// Handle the request based on the URL
N_STR* origin = new_nstr(32);
nstrprintf(origin, "%s:" SOCKET_SIZE_FORMAT, _str(netw_ptr->link.ip), netw_ptr->link.sock);
NETWORK_HTTP_INFO http_request = netw_extract_http_info(http_buffer);
N_STR* http_body = NULL;
split_results = split(url, "?", 0);
if (!split_results || !split_results[0]) {
http_body = char_to_nstr("<html><body><h1>Bad Request</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 400, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a Bad Request answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 400", _nstr(origin), http_request.type, url);
} else {
http_url = split_results[0];
n_log(LOG_INFO, "%s: %s %s request...", _nstr(origin), http_request.type, url);
if (strcmp("OPTIONS", http_request.type) == 0) {
if (build_secure_response(&dynamic_request_answer, 200, netw_guess_http_content_type(url), "Allow: OPTIONS, GET, POST\r\n", NULL) == FALSE) {
n_log(LOG_ERR, "couldn't build an OPTION answer for %s", url);
}
n_log(LOG_INFO, "%s: %s %s 200", _nstr(origin), http_request.type, url);
} else if (strcmp("GET", http_request.type) == 0) {
char system_url[4096] = "";
const char* effective_root = root_dir ? root_dir : "./DATAS";
snprintf(system_url, sizeof(system_url), "%s%s", effective_root, http_url);
n_log(LOG_DEBUG, "%s: searching for file %s...", _nstr(origin), system_url);
/* Path traversal protection: validate resolved path is within root */
char validated_path[PATH_MAX] = "";
if (!validate_path(system_url, effective_root, validated_path, sizeof(validated_path))) {
/* Either file doesn't exist or path escapes root */
struct stat st;
if (stat(system_url, &st) == 0) {
/* File exists but outside root: forbidden */
n_log(LOG_ERR, "%s: path traversal blocked for %s", _nstr(origin), url);
http_body = char_to_nstr("<html><body><h1>403 Forbidden</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 403, "text/html", "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a Forbidden answer for %s", url);
}
} else {
/* File doesn't exist: 404 */
http_body = char_to_nstr("<html><body><h1>404 Not Found</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 404, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a NOT FOUND answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 404", _nstr(origin), http_request.type, url);
}
} else {
struct stat st;
if (stat(validated_path, &st) == 0 && S_ISREG(st.st_mode)) {
n_log(LOG_DEBUG, "%s: file %s found !", _nstr(origin), validated_path);
http_body = file_to_nstr(validated_path);
if (!http_body) {
http_body = char_to_nstr("<html><body><h1>Internal Server Error</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 500, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build an Internal Server Error answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 500", _nstr(origin), http_request.type, url);
} else {
if (build_secure_response(&dynamic_request_answer, 200, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build an http answer for %s", url);
}
n_log(LOG_INFO, "%s: %s %s 200", _nstr(origin), http_request.type, url);
}
} else if (stat(validated_path, &st) == 0 && S_ISDIR(st.st_mode)) {
/* Directory: check for index.html and redirect */
char index_path[PATH_MAX + 16] = "";
size_t url_len = strlen(http_url);
const char* url_slash = (url_len > 0 && http_url[url_len - 1] == '/') ? "" : "/";
/* realpath never has a trailing slash, always add '/' for filesystem path */
size_t vp_len = strlen(validated_path);
if (vp_len + sizeof("/index.html") > sizeof(index_path)) {
n_log(LOG_ERR, "path too long for index lookup: %s", validated_path);
http_body = char_to_nstr("<html><body><h1>414 URI Too Long</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 414, "text/html", "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a URI Too Long answer for %s", url);
}
} else {
snprintf(index_path, sizeof(index_path), "%s/index.html", validated_path);
char validated_index[PATH_MAX] = "";
struct stat idx_st;
if (validate_path(index_path, effective_root, validated_index, sizeof(validated_index)) &&
stat(validated_index, &idx_st) == 0 && S_ISREG(idx_st.st_mode)) {
char location_header[4096] = "";
snprintf(location_header, sizeof(location_header), "Location: %s%sindex.html\r\n", http_url, url_slash);
if (build_secure_response(&dynamic_request_answer, 301, "text/html", location_header, NULL) == FALSE) {
n_log(LOG_ERR, "couldn't build a redirect answer for %s", url);
}
n_log(LOG_INFO, "%s: %s %s 301 -> %s%sindex.html", _nstr(origin), http_request.type, url, http_url, url_slash);
} else {
http_body = char_to_nstr("<html><body><h1>404 Not Found</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 404, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a NOT FOUND answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 404", _nstr(origin), http_request.type, url);
}
}
} else {
http_body = char_to_nstr("<html><body><h1>404 Not Found</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 404, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a NOT FOUND answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 404", _nstr(origin), http_request.type, url);
}
}
} else if (strcmp("POST", http_request.type) == 0) {
// Parse virtual route
found = 0;
list_foreach(node, routes_ptr) {
if (strcmp(node->ptr, http_url) == 0) {
// Handle 200 OK from virtual route
HASH_TABLE* post_data = netw_parse_post_data(http_request.body);
if (post_data) {
HT_FOREACH(hnode, post_data,
{
n_log(LOG_DEBUG, "%s: POST DATA: %s=%s", _nstr(origin), hnode->key, (char*)hnode->data.ptr);
});
destroy_ht(&post_data);
}
http_body = char_to_nstr("{\"status\":\"ok\"}");
if (build_secure_response(&dynamic_request_answer, 200, "application/json", "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a route 200 answer for %s", url);
}
found = 1;
n_log(LOG_INFO, "%s: %s virtual:%s 200", _nstr(origin), http_request.type, url);
break;
}
}
if (!found) {
http_body = char_to_nstr("<html><body><h1>404 Not Found</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 404, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a NOT FOUND answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 404", _nstr(origin), http_request.type, url);
}
} else {
http_body = char_to_nstr("<html><body><h1>400 Bad Request</h1></body></html>");
if (build_secure_response(&dynamic_request_answer, 400, netw_guess_http_content_type(url), "", http_body) == FALSE) {
n_log(LOG_ERR, "couldn't build a Bad Request answer for %s", url);
}
n_log(LOG_ERR, "%s: %s %s 400", _nstr(origin), http_request.type, url);
}
free_split_result(&split_results);
}
if (dynamic_request_answer) {
if (dynamic_request_answer->written > UINT32_MAX) {
n_log(LOG_ERR, "response too large to send for %s: %s %s (size: %zu)", _nstr(origin), http_request.type, url, dynamic_request_answer->written);
} else if (send_ssl_data(netw_ptr, dynamic_request_answer->data, (uint32_t)dynamic_request_answer->written) < 0) {
n_log(LOG_ERR, "failed to send response for %s: %s %s", _nstr(origin), http_request.type, url);
}
free_nstr(&dynamic_request_answer);
} else {
n_log(LOG_ERR, "couldn't build an answer for %s: %s %s", _nstr(origin), http_request.type, url);
}
netw_info_destroy(http_request);
free_nstr(&origin);
free_nstr(&http_body);
Free(http_buffer);
} /* handle_request */
typedef struct NETWORK_SSL_THREAD_PARAMS {
NETWORK* netw;
LIST* routes;
} NETWORK_SSL_THREAD_PARAMS;
void* ssl_network_thread(void* params) {
__n_assert(params, return NULL);
NETWORK_SSL_THREAD_PARAMS* ssl_params = (NETWORK_SSL_THREAD_PARAMS*)params;
handle_request(ssl_params->netw, ssl_params->routes);
netw_close(&ssl_params->netw);
Free(ssl_params);
return NULL;
}
int main(int argc, char* argv[]) {
int exit_code = 0;
int crypto_ok = FALSE;
THREAD_POOL* thread_pool = NULL;
routes = new_generic_list(MAX_LIST_ITEMS);
__n_assert(routes, n_log(LOG_ERR, "could not allocate list !"); exit(1));
/* processing args and set log_level */
process_args(argc, argv, &addr, &port, &key, &cert, &ca_file, &ssl_verify, routes, &ip_version, &max_http_request_size, &root_dir);
if (!port) {
n_log(LOG_ERR, "No port given. Exiting.");
exit_code = 1;
goto clean_and_exit;
}
if (!key) {
n_log(LOG_ERR, "No key given. Exiting.");
exit_code = 1;
goto clean_and_exit;
}
if (!cert) {
n_log(LOG_ERR, "No certificate given. Exiting.");
exit_code = 1;
goto clean_and_exit;
}
#ifndef __windows__
errno = 0;
signal(SIGPIPE, SIG_IGN);
/* initializing signal catching */
struct sigaction signal_catcher;
/* quit on sig */
signal_catcher.sa_handler = action_on_sig;
sigemptyset(&signal_catcher.sa_mask);
signal_catcher.sa_flags = 0;
sigaction(SIGTERM, &signal_catcher, NULL);
sigaction(SIGUSR1, &signal_catcher, NULL);
#endif
long int cores = get_nb_cpu_cores();
int nb_active_threads = (cores > 0) ? (int)cores : 1;
int nb_waiting_threads = 10 * nb_active_threads;
n_log(LOG_INFO, "Creating a new thread pool of %d active and %d waiting threads", nb_active_threads, nb_waiting_threads);
thread_pool = new_thread_pool((size_t)nb_active_threads, (size_t)nb_waiting_threads);
n_log(LOG_INFO, "Creating listening network for %s:%s %d", _str(addr), _str(port), ip_version);
/* create listening network */
if (netw_make_listening(&server, addr, port, SOMAXCONN, ip_version) == FALSE) {
n_log(LOG_ERR, "Fatal error with network initialization");
exit(-1);
}
/* an unreadable or malformed key/cert leaves the listener in plaintext,
* which then fails every client handshake, so treat it as fatal here */
if (ca_file) {
n_log(LOG_INFO, "Using SSL with certificate chain verification (CA: %s)", ca_file);
crypto_ok = netw_set_crypto_chain(server, key, cert, ca_file);
} else {
crypto_ok = netw_set_crypto(server, key, cert);
}
if (crypto_ok == FALSE) {
n_log(LOG_ERR, "Could not load key '%s' and certificate '%s'. Exiting.", _str(key), _str(cert));
exit_code = 1;
goto clean_and_exit;
}
/* Harden the SSL context after crypto setup */
if (ssl_harden_context(server) == FALSE) {
n_log(LOG_ERR, "Failed to harden SSL context. Exiting.");
exit_code = 1;
goto clean_and_exit;
}
if (ssl_verify) {
n_log(LOG_INFO, "SSL peer certificate verification enabled");
netw_ssl_set_verify(server, 1);
}
int accepted_count = 0;
/* idle watchdog: get_msec() gives the delta since the previous poll, so
* accumulating it measures the time since the last accepted connection */
N_TIME idle_timer;
start_HiTimer(&idle_timer);
time_t idle_msec = 0;
while (!done) {
n_log(LOG_DEBUG, "Waiting on accept...");
/* A 500ms accept window rather than a blocking accept: it is the only
* way the `done` flag raised by the signal handler is ever seen, and
* it lets the watchdog below fire when no client ever shows up
* instead of sitting here until the test harness kills us */
int return_code = 0;
netw = netw_accept_from_ex(server, 0, 0, 500, &return_code);
if (!netw) {
idle_msec += get_msec(&idle_timer);
if (return_code == EINTR) {
/* a signal cut select() short. Do not leave here: the loop
* condition is what decides whether that signal asked us to
* stop, and leaving directly would skip the status below */
n_log(LOG_INFO, "accept interrupted by a signal");
} else if (return_code != 0 && return_code != EAGAIN && return_code != EWOULDBLOCK) {
/* 0 / EAGAIN / EWOULDBLOCK just mean the window expired with
* nothing waiting, which is the normal idle case */
n_log(LOG_ERR, "error on accept, NULL netw returned !");
u_sleep(100000);
}
if (accept_timeout > 0 && idle_msec > (time_t)accept_timeout * 1000) {
n_log(LOG_ERR, "no connection for %d seconds, giving up with %d accepted", accept_timeout, accepted_count);
exit_code = 1;
break;
}
continue;
}
n_log(LOG_INFO, "accepted SSL connection on socket %d", netw->link.sock);
NETWORK_SSL_THREAD_PARAMS* netw_ssl_params = NULL;
Malloc(netw_ssl_params, NETWORK_SSL_THREAD_PARAMS, 1);
netw_ssl_params->netw = netw;
netw_ssl_params->routes = routes;
if (add_threaded_process(thread_pool, &ssl_network_thread, (void*)netw_ssl_params, DIRECT_PROC) == FALSE) {
n_log(LOG_ERR, "Error adding client management to thread pool");
}
accepted_count++;
idle_msec = 0;
get_msec(&idle_timer);
if (max_connections > 0 && accepted_count >= max_connections) {
n_log(LOG_NOTICE, "reached %d connections, exiting", max_connections);
break;
}
}
if (killed_by_signal) {
n_log(LOG_ERR, "caught SIGTERM, shutting down after %d connections", accepted_count);
exit_code = 1;
}
clean_and_exit:
if (thread_pool) {
wait_for_threaded_pool(thread_pool);
destroy_threaded_pool(&thread_pool, 1000);
}
netw_close(&server);
netw_unload();
list_destroy(&routes);
FreeNoLog(addr);
FreeNoLog(port);
FreeNoLog(key);
FreeNoLog(cert);
FreeNoLog(ca_file);
FreeNoLog(root_dir);
exit(exit_code);
}
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB