diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-03-11 22:45:56 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-03-11 22:45:56 +0000 |
commit | 0746baa7c3e4924ac6a687d0d1fff3b33138eca0 (patch) | |
tree | 22fd4320a4eb7323e817b6e4ac878dec168d65d1 /src/util | |
parent | 494f33365cb6b1c8d290fb6ad06aa6be45b880a7 (diff) | |
download | gnunet-0746baa7c3e4924ac6a687d0d1fff3b33138eca0.tar.gz gnunet-0746baa7c3e4924ac6a687d0d1fff3b33138eca0.zip |
-LRN: Generalize ip-address str->addr conversion
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/strings.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/util/strings.c b/src/util/strings.c index abc763b88..a6a5c7542 100644 --- a/src/util/strings.c +++ b/src/util/strings.c | |||
@@ -950,4 +950,136 @@ GNUNET_STRINGS_check_filename (const char *filename, | |||
950 | return GNUNET_YES; | 950 | return GNUNET_YES; |
951 | } | 951 | } |
952 | 952 | ||
953 | #define MAX_IPV6_ADDRLEN 47 | ||
954 | #define MAX_IPV4_ADDRLEN 21 | ||
955 | #define MAX_IP_ADDRLEN MAX_IPV6_ADDRLEN | ||
956 | |||
957 | /** | ||
958 | * Tries to convert @zt_addr string to an IPv6 address. | ||
959 | * | ||
960 | * @param zt_addr 0-terminated string. May be mangled by the function. | ||
961 | * @param addrlen length of zt_addr (not counting 0-terminator). | ||
962 | * @param r_buf a buffer to fill. Initially gets filled with zeroes, | ||
963 | * then its sin6_port, sin6_family and sin6_addr are set appropriately. | ||
964 | * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which | ||
965 | * case the contents of r_buf are undefined. | ||
966 | */ | ||
967 | int | ||
968 | GNUNET_STRINGS_to_address_ipv6 (char *zt_addr, uint16_t addrlen, | ||
969 | struct sockaddr_in6 *r_buf) | ||
970 | { | ||
971 | int ret; | ||
972 | char *port_colon; | ||
973 | unsigned int port; | ||
974 | |||
975 | if (addrlen < 6) | ||
976 | return GNUNET_SYSERR; | ||
977 | |||
978 | port_colon = strrchr (zt_addr, ':'); | ||
979 | if (port_colon == NULL) | ||
980 | return GNUNET_SYSERR; | ||
981 | ret = sscanf (port_colon, ":%u", &port); | ||
982 | if (ret != 1 || port > 65535) | ||
983 | return GNUNET_SYSERR; | ||
984 | port_colon[0] = '\0'; | ||
985 | |||
986 | memset (r_buf, 0, sizeof (struct sockaddr_in6)); | ||
987 | ret = inet_pton (AF_INET6, zt_addr, &r_buf->sin6_addr); | ||
988 | if (ret <= 0) | ||
989 | return GNUNET_SYSERR; | ||
990 | r_buf->sin6_port = htonl (port); | ||
991 | r_buf->sin6_family = AF_INET6; | ||
992 | return GNUNET_OK; | ||
993 | } | ||
994 | |||
995 | /** | ||
996 | * Tries to convert @zt_addr string to an IPv4 address. | ||
997 | * | ||
998 | * @param zt_addr 0-terminated string. May be mangled by the function. | ||
999 | * @param addrlen length of zt_addr (not counting 0-terminator). | ||
1000 | * @param r_buf a buffer to fill. | ||
1001 | * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case | ||
1002 | * the contents of r_buf are undefined. | ||
1003 | */ | ||
1004 | int | ||
1005 | GNUNET_STRINGS_to_address_ipv4 (char *zt_addr, uint16_t addrlen, | ||
1006 | struct sockaddr_in *r_buf) | ||
1007 | { | ||
1008 | unsigned int temps[5]; | ||
1009 | unsigned int port; | ||
1010 | int cnt; | ||
1011 | |||
1012 | if (addrlen < 9) | ||
1013 | return GNUNET_SYSERR; | ||
1014 | |||
1015 | cnt = sscanf (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); | ||
1016 | if (cnt != 5) | ||
1017 | return GNUNET_SYSERR; | ||
1018 | |||
1019 | for (cnt = 0; cnt < 4; cnt++) | ||
1020 | if (temps[cnt] > 0xFF) | ||
1021 | return GNUNET_SYSERR; | ||
1022 | if (port > 65535) | ||
1023 | return GNUNET_SYSERR; | ||
1024 | |||
1025 | r_buf->sin_family = AF_INET; | ||
1026 | r_buf->sin_port = htonl (port); | ||
1027 | r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + | ||
1028 | (temps[2] << 8) + temps[3]); | ||
1029 | return GNUNET_OK; | ||
1030 | } | ||
1031 | |||
1032 | /** | ||
1033 | * Tries to convert @addr string to an IP (v4 or v6) address. | ||
1034 | * IPv6 address must have its address part enclosed in '()' parens | ||
1035 | * instead of '[]'. | ||
1036 | * Will automatically decide whether to treat @addr as v4 or v6 address. | ||
1037 | * | ||
1038 | * @param addr a string, may not be 0-terminated. | ||
1039 | * @param addrlen number of bytes in addr (if addr is 0-terminated, | ||
1040 | * 0-terminator should not be counted towards addrlen). | ||
1041 | * @param r_buf a buffer to fill. | ||
1042 | * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which | ||
1043 | * case the contents of r_buf are undefined. | ||
1044 | */ | ||
1045 | int | ||
1046 | GNUNET_STRINGS_to_address_ip (const char *addr, uint16_t addrlen, | ||
1047 | struct sockaddr_storage *r_buf) | ||
1048 | { | ||
1049 | uint16_t i; | ||
1050 | char zt_addr[MAX_IP_ADDRLEN + 1]; | ||
1051 | uint16_t zt_len = addrlen <= MAX_IP_ADDRLEN ? addrlen : MAX_IP_ADDRLEN; | ||
1052 | |||
1053 | if (addrlen < 1) | ||
1054 | return GNUNET_SYSERR; | ||
1055 | |||
1056 | memset (zt_addr, 0, MAX_IP_ADDRLEN + 1); | ||
1057 | strncpy (zt_addr, addr, zt_len); | ||
1058 | |||
1059 | /* For URIs we use '(' and ')' instead of '[' and ']'. Do the substitution | ||
1060 | * now, as GNUNET_STRINGS_to_address_ipv6() takes a proper []-enclosed IPv6 | ||
1061 | * address. | ||
1062 | */ | ||
1063 | if (zt_addr[0] == '(') | ||
1064 | { | ||
1065 | for (i = 0; i < zt_len; i++) | ||
1066 | { | ||
1067 | switch (zt_addr[i]) | ||
1068 | { | ||
1069 | case '(': | ||
1070 | zt_addr[i] = '['; | ||
1071 | break; | ||
1072 | case ')': | ||
1073 | zt_addr[i] = ']'; | ||
1074 | break; | ||
1075 | default: | ||
1076 | break; | ||
1077 | } | ||
1078 | } | ||
1079 | return GNUNET_STRINGS_to_address_ipv6 (zt_addr, zt_len, (struct sockaddr_in6 *) r_buf); | ||
1080 | } | ||
1081 | else | ||
1082 | return GNUNET_STRINGS_to_address_ipv4 (zt_addr, zt_len, (struct sockaddr_in *) r_buf); | ||
1083 | } | ||
1084 | |||
953 | /* end of strings.c */ | 1085 | /* end of strings.c */ |