Helium
he.h
Go to the documentation of this file.
1 /* *
2  * Lightway Core
3  * Copyright (C) 2021 Express VPN International Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
32 #ifndef HE
33 #define HE
34 
35 // Needed headers
36 #include <stdbool.h>
37 #include <stdint.h>
38 
39 // Network headers
40 #include "he_plugin.h"
41 
42 // WolfSSL
43 #ifndef WOLFSSL_USER_SETTINGS
44 #include <wolfssl/options.h>
45 #endif
46 #include <wolfssl/ssl.h>
47 #include <wolfssl/wolfcrypt/settings.h>
48 #include <wolfssl/wolfcrypt/random.h>
49 
50 // Helper macros
51 
53 #define HE_MAX_WIRE_MTU 1500
54 #define HE_MAX_MTU 1350
55 #define HE_MAX_MTU_STR "1350"
56 
58 #define HE_WIRE_MINIMUM_PROTOCOL_MAJOR_VERSION 1
59 #define HE_WIRE_MINIMUM_PROTOCOL_MINOR_VERSION 0
60 #define HE_WIRE_MAXIMUM_PROTOCOL_MAJOR_VERSION 1
61 #define HE_WIRE_MAXIMUM_PROTOCOL_MINOR_VERSION 1
62 
65 #ifdef __GNUC__
67 #define HE_DEPRECATED(name) __attribute__((deprecated("use " #name " instead")))
68 #elif defined(_MSC_VER)
69 #define HE_DEPRECATED(name) __declspec(deprecated("use " #name " instead"))
70 #endif
71 
73 #define HE_CONFIG_TEXT_FIELD_LENGTH 50
74 #define HE_MAX_IPV4_STRING_LENGTH 24
76 
80 typedef enum he_return_code {
198 
202 typedef enum he_conn_state {
221 
222 typedef enum he_conn_event {
236 } he_conn_event_t;
237 
242 typedef enum he_padding_type {
250 
254 typedef enum he_connection_type {
260 
261 typedef struct he_ssl_ctx he_ssl_ctx_t;
262 typedef struct he_conn he_conn_t;
263 typedef struct he_plugin_chain he_plugin_chain_t;
265 
270 typedef struct he_client {
271  he_ssl_ctx_t *ssl_ctx;
272  he_conn_t *conn;
273  he_plugin_chain_t *inside_plugins;
274  he_plugin_chain_t *outside_plugins;
275 } he_client_t;
276 
277 typedef void *(*he_malloc_t)(size_t size);
278 typedef void *(*he_calloc_t)(size_t nmemb, size_t size);
279 typedef void *(*he_realloc_t)(void *ptr, size_t size);
280 typedef void (*he_free_t)(void *ptr);
281 
292  void *context);
293 
305 typedef he_return_code_t (*he_inside_write_cb_t)(he_conn_t *conn, uint8_t *packet, size_t length,
306  void *context);
307 
319 typedef he_return_code_t (*he_outside_write_cb_t)(he_conn_t *conn, uint8_t *packet, size_t length,
320  void *context);
321 
333  he_network_config_ipv4_t *config,
334  void *context);
335 
345 typedef he_return_code_t (*he_event_cb_t)(he_conn_t *conn, he_conn_event_t event, void *context);
346 
367 typedef he_return_code_t (*he_nudge_time_cb_t)(he_conn_t *conn, int timeout, void *context);
368 
381 typedef bool (*he_auth_cb_t)(he_conn_t *conn, char const *username, char const *password,
382  void *context);
383 
396 typedef bool (*he_auth_buf_cb_t)(he_conn_t *conn, uint8_t auth_type, uint8_t *buffer,
397  uint16_t length, void *context);
398 
411  he_network_config_ipv4_t *config,
412  void *context);
413 
416 typedef struct he_packet_buffer {
417  // Buffer has data
418  bool has_packet;
419  // Size of packet
420  int packet_size;
421  // The packet itself
422  uint8_t packet[HE_MAX_WIRE_MTU];
424 
425 // Note that this is *not* intended for use on the wire; this struct is part of
426 // the internal API and just conveniently connects these two numbers together.
427 typedef struct he_version_info {
428  // Version of the wire protocol
429  uint8_t major_version;
430  uint8_t minor_version;
432 
433 struct he_ssl_ctx {
435  char server_dn[HE_CONFIG_TEXT_FIELD_LENGTH + 1];
438  // Location of Client CA certificate in PEM format
439  uint8_t *cert_buffer;
442 
443  // Server certificate location
444  char const *server_cert;
445  // Server certificate key location
446  char const *server_key;
447 
448  he_connection_type_t connection_type;
459  // Callback for events
460  he_event_cb_t event_cb;
461  // Callbacks for auth (server-only)
462  he_auth_cb_t auth_cb;
463  he_auth_buf_cb_t auth_buf_cb;
464  // Callback for populating the network config (server-only)
465  he_populate_network_config_ipv4_cb_t populate_network_config_ipv4_cb;
472 
474  WOLFSSL_CTX *wolf_ctx;
475  // Random number generator
476  RNG wolf_rng;
477 
480  he_version_info_t maximum_supported_version;
481 };
482 
483 struct he_conn {
487  bool is_server;
488 
491 
493  uint8_t *incoming_data;
496  // WolfSSL stuff
497  WOLFSSL *wolf_ssl;
501  uint8_t write_buffer[HE_MAX_WIRE_MTU];
505  uint64_t session_id;
506  uint64_t pending_session_id;
515 
516  bool renegotiation_in_progress;
517  bool renegotiation_due;
518 
521 
522  he_plugin_chain_t *inside_plugins;
523  he_plugin_chain_t *outside_plugins;
524 
525  uint8_t auth_type;
526 
528  char username[HE_CONFIG_TEXT_FIELD_LENGTH + 1];
530  char password[HE_CONFIG_TEXT_FIELD_LENGTH + 1];
531 
532  uint8_t auth_buffer[HE_MAX_MTU];
533  uint16_t auth_buffer_length;
534 
537 
538  void *data;
539 
540  // Data from the SSL contxt config copied here to make this hermetic
549 
560  // Callback for events
561  he_event_cb_t event_cb;
562  // Callback for auth (server-only)
563  he_auth_cb_t auth_cb;
564  he_auth_buf_cb_t auth_buf_cb;
565  // Callback for populating the network config (server-only)
566  he_populate_network_config_ipv4_cb_t populate_network_config_ipv4_cb;
567 
570 
572  RNG wolf_rng;
573 };
574 
576  plugin_struct_t *plugin;
577  he_plugin_chain_t *next;
578 };
579 
580 // MSG IDs
581 typedef enum msg_ids {
608 } msg_ids_t;
609 
610 typedef enum he_auth_type { HE_AUTH_TYPE_USERPASS = 1 } he_auth_type_t;
611 
614 typedef struct he_network_config_ipv4 {
615  char local_ip[HE_MAX_IPV4_STRING_LENGTH];
616  char peer_ip[HE_MAX_IPV4_STRING_LENGTH];
617  char dns_ip[HE_MAX_IPV4_STRING_LENGTH];
618  int mtu;
620 
621 #pragma pack(1)
622 
629 typedef struct he_wire_hdr {
630  // First two bytes to contain the 'H' and 'e'
631  char he[2];
632  // Version of the wire protocol
633  uint8_t major_version;
634  uint8_t minor_version;
635  // Request aggressive mode
636  uint8_t aggressive_mode;
637  // Three bytes reserved for future use
638  uint8_t reserved[3];
639  // 64 bit session identifier
640  uint64_t session;
641 } he_wire_hdr_t;
642 
645 typedef struct he_msg_hdr {
646  uint8_t msgid;
647 } he_msg_hdr_t;
648 
649 typedef struct he_msg_ping {
650  he_msg_hdr_t msg_header;
651  uint32_t payload;
652 } he_msg_ping_t;
653 
654 typedef struct he_msg_pong {
655  he_msg_hdr_t msg_header;
656  uint32_t payload;
657 } he_msg_pong_t;
658 
659 typedef struct he_msg_auth_hdr {
660  he_msg_hdr_t msg_header;
661  uint8_t auth_type;
663 
664 typedef struct he_msg_auth {
665  he_msg_auth_hdr_t header;
666  uint8_t username_length;
667  uint8_t password_length;
668  char username[HE_CONFIG_TEXT_FIELD_LENGTH];
669  char password[HE_CONFIG_TEXT_FIELD_LENGTH];
670 } he_msg_auth_t;
671 
672 typedef struct he_msg_auth_buf {
673  he_msg_auth_hdr_t header;
674  uint16_t buffer_length;
675  uint8_t buffer[];
677 
678 typedef struct he_msg_config_ipv4 {
679  he_msg_hdr_t msg_header;
680  char local_ip[HE_MAX_IPV4_STRING_LENGTH];
681  char peer_ip[HE_MAX_IPV4_STRING_LENGTH];
682  char dns_ip[HE_MAX_IPV4_STRING_LENGTH];
683  char mtu[HE_MAX_IPV4_STRING_LENGTH];
684  uint64_t session;
686 
687 typedef struct he_msg_data {
688  he_msg_hdr_t msg_header;
689  uint16_t length;
690 } he_msg_data_t;
691 
692 typedef struct he_deprecated_msg_13 {
693  he_msg_hdr_t msg_header;
694  uint16_t length;
695  uint16_t _unused;
697 
698 #define HE_AUTH_STATUS_SUCCESS 0
699 #define HE_AUTH_STATUS_FAILURE 1
700 
701 typedef struct he_msg_auth_response {
702  he_msg_hdr_t msg_header;
703  uint8_t status;
704  uint8_t status_msg_length;
705  char status_msg[HE_CONFIG_TEXT_FIELD_LENGTH];
707 
708 typedef struct he_msg_session_request {
709  he_msg_hdr_t msg_header;
711 
712 typedef struct he_msg_session_response {
713  he_msg_hdr_t msg_header;
714  uint64_t session;
716 
717 typedef struct he_msg_goodbye {
718  he_msg_hdr_t msg_header;
720 
721 #define HE_EXT_TYPE_REQUEST 1
722 #define HE_EXT_TYPE_RESPONSE 2
723 
724 #define HE_EXT_ID_BLOCK_DNS_OVER_TLS 1
725 
726 #define HE_EXT_PAYLOAD_TYPE_MSGPACK 1
727 #define HE_EXT_PAYLOAD_TYPE_BINARY 2
728 #define HE_EXT_PAYLOAD_TYPE_INT16 3
729 
730 typedef struct he_msg_extension {
731  he_msg_hdr_t msg_header;
732  uint16_t extension_id;
733  uint8_t msg_type;
734  uint8_t payload_type;
735  uint16_t payload_length;
736  uint8_t data;
737 
739 
741 #pragma pack()
742 
744 static const uint64_t HE_PACKET_SESSION_REJECT = 0xFFFFFFFFFFFFFFFF;
745 static const uint64_t HE_PACKET_SESSION_EMPTY = 0x0000000000000000;
746 
749 // D/TLS headers + AES crypto fields
750 #define HE_WOLF_MAX_HEADER_SIZE 37
751 #define HE_IPV4_HEADER_SIZE 20
752 #define HE_TCP_HEADER_SIZE 20
753 #define HE_UDP_HEADER_SIZE 8
754 // Add a gap to avoid normal ADSL / PPPoX type overhead
755 #define HE_HEADER_SAFE_GAP 28
756 static const size_t HE_PACKET_OVERHEAD = sizeof(he_deprecated_msg_13_t) + sizeof(he_wire_hdr_t) +
757  HE_IPV4_HEADER_SIZE + HE_UDP_HEADER_SIZE +
758  HE_WOLF_MAX_HEADER_SIZE + HE_HEADER_SAFE_GAP;
759 
760 #define HE_MSS_OVERHEAD (HE_IPV4_HEADER_SIZE + HE_UDP_HEADER_SIZE)
761 
762 #endif
Connection is currently trying to establish a D/TLS session with the server.
Definition: he.h:209
Definition: he.h:692
Ping reqest.
Definition: he.h:585
The wire header format It is strongly discouraged to interact with this header structure, however, it is provided for specific use cases (such as a server rejecting a session, where by definition we don&#39;t have a connection object).
Definition: he.h:629
First packet / message was passed to Helium (i.e. a server response)
Definition: he.h:224
The connection was closed.
Definition: he.h:148
Callback failed.
Definition: he.h:152
RNG wolf_rng
Random number generator.
Definition: he.h:572
he_return_code_t(* he_nudge_time_cb_t)(he_conn_t *conn, int timeout, void *context)
The prototype for the nudge time callback function.
Definition: he.h:367
A negative value was given but only an unsigned value is acceptable.
Definition: he.h:104
he_return_code_t(* he_event_cb_t)(he_conn_t *conn, he_conn_event_t event, void *context)
The prototype for the event callback function.
Definition: he.h:345
Password not set in config.
Definition: he.h:128
Packet provided was too large.
Definition: he.h:172
This will be returned if a function was called against a connection context that isn&#39;t in a good stat...
Definition: he.h:94
enum he_return_code he_return_code_t
All possible return codes for helium.
Helium is not connected.
Definition: he.h:144
A null pointer was passed as an argument.
Definition: he.h:96
enum he_connection_type he_connection_type_t
Helium can operate in datagram or stream modes. This enum defines these two modes.
Definition: he.h:433
TLS link is up.
Definition: he.h:215
he_network_config_ipv4_cb_t network_config_ipv4_cb
Network config callback.
Definition: he.h:559
Definition: he.h:575
uint8_t * incoming_data_read_offset_ptr
Index into the incoming data buffer.
Definition: he.h:514
he_version_info_t minimum_supported_version
Supported versions for this context.
Definition: he.h:479
NOOP - nothing to do.
Definition: he.h:583
Packet provided does not have a Helium header.
Definition: he.h:110
Helium needs to write more data before it can continue.
Definition: he.h:136
MTU not set in config.
Definition: he.h:132
Helium only supports IPv4 and IPv6.
Definition: he.h:146
Auth response with config (fast login)
Definition: he.h:597
he_packet_buffer_t read_packet
Read packet buffers // Datagram only.
Definition: he.h:508
The packet was invalid (wrong length, bad type etc)
Definition: he.h:150
The SSL layer was not able to allocate more memory.
Definition: he.h:116
he_return_code
All possible return codes for helium.
Definition: he.h:80
int wolf_timeout
Wolf Timeout.
Definition: he.h:499
Tell Helium not to pad packets at all.
Definition: he.h:244
he_inside_write_cb_t inside_write_cb
Callback for writing to the inside (i.e. a TUN device)
Definition: he.h:555
Definition: he.h:162
Disconnect due to inactivity timeout.
Definition: he.h:174
Deprecated message - same as Data packet with an unused int flag.
Definition: he.h:607
Stream mode (i.e. TCP)
Definition: he.h:258
he_return_code_t(* he_inside_write_cb_t)(he_conn_t *conn, uint8_t *packet, size_t length, void *context)
The prototype for the inside write callback function.
Definition: he.h:305
he_connection_type
Helium can operate in datagram or stream modes. This enum defines these two modes.
Definition: he.h:254
Definition: he.h:672
Tell the other side that we&#39;re closing down.
Definition: he.h:605
uint64_t session_id
Session ID.
Definition: he.h:505
The SSL Connection has failed due to timeout.
Definition: he.h:142
Client has both username/password set AND authentication buffer set.
Definition: he.h:192
Initialisation failed - this is usually an issue with the SSL layer.
Definition: he.h:106
struct he_network_config_ipv4 he_network_config_ipv4_t
Definition: he.h:264
he_nudge_time_cb_t nudge_time_cb
Nudge timer.
Definition: he.h:553
Outside write callback not set in config.
Definition: he.h:138
struct he_client he_client_t
Data structure to hold all the state needed as a Helium client.
Helium has started a secure renegotiation.
Definition: he.h:231
Auth callback not set on a server.
Definition: he.h:182
bool use_aggressive_mode
Use aggressive mode.
Definition: he.h:546
he_padding_type
Helium supports numerous padding levels, from none to full. This enum defines which options can be ch...
Definition: he.h:242
Definition: he_plugin.h:49
Definition: he.h:687
struct he_wire_hdr he_wire_hdr_t
The wire header format It is strongly discouraged to interact with this header structure, however, it is provided for specific use cases (such as a server rejecting a session, where by definition we don&#39;t have a connection object).
bool packet_seen
Packet seen.
Definition: he.h:503
bool(* he_auth_cb_t)(he_conn_t *conn, char const *username, char const *password, void *context)
The prototype for the authentication callback.
Definition: he.h:381
he_conn_state_t state
Client State.
Definition: he.h:490
Configuring - config has been received and config callback will soon be made.
Definition: he.h:219
Generic issue with the SSL layer.
Definition: he.h:124
CA not set in config.
Definition: he.h:130
Connection has yet to be initialised.
Definition: he.h:204
Definition: he.h:659
enum he_conn_state he_conn_state_t
Status codes for a Helium connection.
Definition: he.h:207
he_outside_write_cb_t outside_write_cb
Callback for writing to the outside (i.e. a socket)
Definition: he.h:557
The SSL certificate is not in the correct format.
Definition: he.h:118
he_conn_state
Status codes for a Helium connection.
Definition: he.h:202
he_version_info_t protocol_version
Connection version – set on client side, accepted on server side.
Definition: he.h:569
An empty packet was passed to the function. Either a NULL pointer or a length of zero.
Definition: he.h:98
Authentication Request (only server should see this)
Definition: he.h:589
he_state_change_cb_t state_change_cb
State callback.
Definition: he.h:450
enum he_padding_type he_padding_type_t
Helium supports numerous padding levels, from none to full. This enum defines which options can be ch...
Inconsistent session received on server side.
Definition: he.h:186
If the function call completed successfully, this will be returned.
Definition: he.h:82
Definition: he.h:701
size_t incoming_data_left_to_read
Bytes left to read in the packet buffer (Streaming only)
Definition: he.h:512
General connection failed error.
Definition: he.h:140
Pong - response to a Ping request.
Definition: he.h:587
Session Response.
Definition: he.h:603
he_inside_write_cb_t inside_write_cb
Callback for writing to the inside (i.e. a TUN device)
Definition: he.h:452
Protocol version for connection changed after creation.
Definition: he.h:190
Definition: he.h:708
Definition: he.h:427
struct he_packet_buffer he_packet_buffer_t
he_conn_event
Definition: he.h:222
Connection has established a D/TLS session and is attempting to authenticate.
Definition: he.h:213
Definition: he.h:730
Definition: he.h:614
MTU size was invalid.
Definition: he.h:164
Auth response.
Definition: he.h:595
int outside_mtu
MTU Helium should use for the outside connection (i.e. Internet)
Definition: he.h:536
The SSL certificate is not in PEM format.
Definition: he.h:112
Pointer would overflow.
Definition: he.h:176
bool disable_roaming_connections
Don&#39;t send session ID in packet header.
Definition: he.h:542
Could not allocate memory.
Definition: he.h:108
Tell Helium to round packets to the nearest 450 bytes.
Definition: he.h:248
Definition: he.h:712
bool(* he_auth_buf_cb_t)(he_conn_t *conn, uint8_t auth_type, uint8_t *buffer, uint16_t length, void *context)
The prototype for the authentication buffer callback.
Definition: he.h:396
he_outside_write_cb_t outside_write_cb
Callback for writing to the outside (i.e. a socket)
Definition: he.h:454
Tell Helium to fully pad packets to the MTU, like IPSEC.
Definition: he.h:246
#define HE_MAX_IPV4_STRING_LENGTH
Maximum size of an IPV4 String.
Definition: he.h:75
The SSL certificate is corrupt or missing.
Definition: he.h:114
Definition: he.h:664
Connection is currently trying to cleanly disconnect from the server.
Definition: he.h:211
bool disable_roaming_connections
Don&#39;t send session ID in packet header.
Definition: he.h:467
Helium Extension message.
Definition: he.h:599
This will be returned if a string parameter is too long to be stored.
Definition: he.h:84
The SSL layer ran out of buffers.
Definition: he.h:120
RNG Failure.
Definition: he.h:180
The internal plugin API definitions.
Definition: he.h:654
he_return_code_t(* he_network_config_ipv4_cb_t)(he_conn_t *conn, he_network_config_ipv4_t *config, void *context)
The prototype for the network config callback function.
Definition: he.h:332
uint8_t * incoming_data
Pointer to incoming data buffer.
Definition: he.h:493
he_padding_type_t padding_type
Which padding type to use.
Definition: he.h:544
A plugin requested that we drop the packet without further processing.
Definition: he.h:184
Server has received an auth_buf message but does not have a handler configured.
Definition: he.h:194
Username not set in config.
Definition: he.h:126
he_state_change_cb_t state_change_cb
State callback.
Definition: he.h:551
he_connection_type_t connection_type
TCP or UDP?
Definition: he.h:548
Session Request.
Definition: he.h:601
Definition: he.h:649
bool is_nudge_timer_running
Do we already have a timer running? If so, we don&#39;t want to generate new callbacks.
Definition: he.h:520
#define HE_CONFIG_TEXT_FIELD_LENGTH
Helpful deprecation macro.
Definition: he.h:73
msg_ids
Definition: he.h:581
Pending Session Acknowledged.
Definition: he.h:235
he_padding_type_t padding_type
Which padding type to use.
Definition: he.h:469
#define HE_WOLF_MAX_HEADER_SIZE
Definition: he.h:750
Server has received an auth_userpass message but does not have a handler configured.
Definition: he.h:196
Definition: he.h:645
#define HE_MAX_WIRE_MTU
Definition: he.h:53
Generic issue with the SSL certificate - the SSL layer did not provide further information.
Definition: he.h:122
Helium has completed secure renegotiation.
Definition: he.h:233
This will be returned if trying to set a configuration parameter to an empty string.
Definition: he.h:86
Helium needs to read more data before it can continue.
Definition: he.h:134
Data packet - contains data to be sent to the tun device.
Definition: he.h:591
he_network_config_ipv4_cb_t network_config_ipv4_cb
Network config callback.
Definition: he.h:456
bool use_aggressive_mode
Use aggressive mode.
Definition: he.h:471
The length parameter was set to zero.
Definition: he.h:102
The packet passed to the function is too small to be valid.
Definition: he.h:100
The server rejected the login.
Definition: he.h:170
Failed to clean up global state.
Definition: he.h:166
Domain Name mismatch - supplied DN didn&#39;t match server certificate.
Definition: he.h:156
Server replied to a PING request (NAT Keepalive)
Definition: he.h:226
bool first_message_received
Has the first message been received?
Definition: he.h:510
Datagram mode (i.e. UDP)
Definition: he.h:256
size_t incoming_data_length
Length of the data in the.
Definition: he.h:495
he_return_code_t(* he_populate_network_config_ipv4_cb_t)(he_conn_t *conn, he_network_config_ipv4_t *config, void *context)
The prototype for the population of the network config.
Definition: he.h:410
bool is_server
Definition: he.h:487
Definition: he.h:416
he_return_code_t(* he_outside_write_cb_t)(he_conn_t *conn, uint8_t *packet, size_t length, void *context)
The prototype for the outside write callback function.
Definition: he.h:319
Data structure to hold all the state needed as a Helium client.
Definition: he.h:270
Connection type argument is not defined in he_connection_type_t.
Definition: he.h:178
struct he_msg_hdr he_msg_hdr_t
Generic issue.
Definition: he.h:154
bool use_chacha
Whether or not to use the CHACHA20 cipher.
Definition: he.h:437
Config.
Definition: he.h:593
The server rejected or couldn&#39;t find our session.
Definition: he.h:168
he_nudge_time_cb_t nudge_time_cb
Nudge timer.
Definition: he.h:458
An SSL error occurred on a D/TLS packet but it does not need to terminate the connection.
Definition: he.h:188
Everything is done - we&#39;re online.
Definition: he.h:217
Definition: he.h:483
size_t cert_buffer_size
The size of the Client CA certificate chain.
Definition: he.h:441
he_return_code_t(* he_state_change_cb_t)(he_conn_t *conn, he_conn_state_t new_state, void *context)
The prototype for the state callback function.
Definition: he.h:291
WOLFSSL_CTX * wolf_ctx
WolfSSL global context.
Definition: he.h:474
Definition: he.h:717
Definition: he.h:678