Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for ipaddr plugin
5 : *
6 : * @copyright BSD License (see doc/LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include <kdberrors.h>
11 : #include <regex.h>
12 : #include <stdio.h>
13 :
14 : #include "ipaddr.h"
15 :
16 36 : static int validateIPv4 (const char * addr)
17 : {
18 36 : if (!addr) return 0;
19 : unsigned int a, b, c, d;
20 36 : a = b = c = d = 0;
21 36 : const char * regexString = "^([0-9]{1,3}\\.){3}([0-9]{1,3})$";
22 : regex_t regex;
23 : regmatch_t offsets;
24 36 : int ret = regcomp (®ex, regexString, REG_NOSUB | REG_EXTENDED | REG_NEWLINE);
25 36 : if (ret) return -1;
26 36 : ret = regexec (®ex, addr, 1, &offsets, 0);
27 36 : regfree (®ex);
28 36 : if (!ret)
29 : {
30 18 : sscanf (addr, "%u.%u.%u.%u", &a, &b, &c, &d);
31 18 : if (a > 255 || b > 255 || c > 255 || d > 255)
32 : {
33 : return 0;
34 : }
35 : else
36 16 : return 1;
37 : }
38 : return 0;
39 : }
40 :
41 35 : static int validateIPv6 (const char * addr)
42 : {
43 35 : if (!addr) return 0;
44 35 : const char * regexString =
45 : "(^((:(([0-9A-Fa-f]{0,4}):){1,6}(([0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4})(:([0-9A-Fa-f]{0,4})){1,7}))$)|(^((:(([0-9A-Fa-f]{"
46 : "0,4}):){1,4}(([0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4})(:([0-9A-Fa-f]{0,4})){1,5}))((([0-9]{1,3}\\.){3})([0-9]{1,3}))$)";
47 : regex_t regex;
48 : regmatch_t offsets;
49 35 : int ret = regcomp (®ex, regexString, REG_NOSUB | REG_EXTENDED | REG_NEWLINE);
50 35 : if (ret) return -1;
51 35 : ret = regexec (®ex, addr, 1, &offsets, 0);
52 35 : regfree (®ex);
53 35 : if (ret)
54 : return 0;
55 : else
56 : {
57 : char * ptr = (char *) addr;
58 : int count = 0;
59 330 : while (*ptr)
60 : {
61 313 : if (*ptr == ':') ++count;
62 313 : ++ptr;
63 : }
64 17 : if (count > 7)
65 : {
66 : return 0;
67 : }
68 17 : else if (count < 7)
69 : {
70 13 : if (!strstr (addr, "::")) return 0;
71 : }
72 15 : if (strchr (addr, '.'))
73 : {
74 2 : char * ipv4ptr = strrchr (addr, ':');
75 2 : ++ipv4ptr;
76 2 : ret = validateIPv4 (ipv4ptr);
77 2 : if (!ret) return 0;
78 : }
79 : return 1;
80 : }
81 : }
82 :
83 60 : static int validateKey (Key * key, Key * parentKey)
84 : {
85 60 : const Key * meta = keyGetMeta (key, "check/ipaddr");
86 60 : if (!meta) return 1;
87 60 : int rc = 0;
88 :
89 60 : if (!strcasecmp (keyString (meta), "ipv4"))
90 : {
91 20 : rc = validateIPv4 (keyString (key));
92 : }
93 40 : else if (!strcasecmp (keyString (meta), "ipv6"))
94 : {
95 26 : rc = validateIPv6 (keyString (key));
96 : }
97 : else
98 : {
99 : // By default we allow both type of addresses
100 14 : if (!(rc = validateIPv4 (keyString (key)))) rc = validateIPv6 (keyString (key));
101 : }
102 :
103 60 : if (!rc)
104 : {
105 31 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Validation of key %s with value %s failed", keyName (key),
106 : keyString (key));
107 : }
108 29 : else if (rc == -1)
109 : {
110 0 : ELEKTRA_SET_OUT_OF_MEMORY_ERROR (parentKey, "Out of memory");
111 0 : rc = 0;
112 : }
113 :
114 : return rc;
115 : }
116 :
117 31 : int elektraIpaddrGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
118 : {
119 31 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/ipaddr"))
120 : {
121 31 : KeySet * contract =
122 31 : ksNew (30, keyNew ("system/elektra/modules/ipaddr", KEY_VALUE, "ipaddr plugin waits for your orders", KEY_END),
123 : keyNew ("system/elektra/modules/ipaddr/exports", KEY_END),
124 : keyNew ("system/elektra/modules/ipaddr/exports/get", KEY_FUNC, elektraIpaddrGet, KEY_END),
125 : keyNew ("system/elektra/modules/ipaddr/exports/set", KEY_FUNC, elektraIpaddrSet, KEY_END),
126 : #include ELEKTRA_README
127 : keyNew ("system/elektra/modules/ipaddr/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
128 31 : ksAppend (returned, contract);
129 31 : ksDel (contract);
130 31 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
131 : }
132 : return ELEKTRA_PLUGIN_STATUS_NO_UPDATE;
133 : }
134 :
135 58 : int elektraIpaddrSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
136 : {
137 : // set all keys
138 : // this function is optional
139 : Key * cur;
140 58 : ksRewind (returned);
141 145 : while ((cur = ksNext (returned)) != NULL)
142 : {
143 60 : const Key * meta = keyGetMeta (cur, "check/ipaddr");
144 60 : if (!meta) continue;
145 60 : int rc = validateKey (cur, parentKey);
146 60 : if (!rc) return ELEKTRA_PLUGIN_STATUS_ERROR;
147 : }
148 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
149 : }
150 :
151 127 : Plugin * ELEKTRA_PLUGIN_EXPORT
152 : {
153 : // clang-format off
154 127 : return elektraPluginExport ("ipaddr",
155 : ELEKTRA_PLUGIN_GET, &elektraIpaddrGet,
156 : ELEKTRA_PLUGIN_SET, &elektraIpaddrSet,
157 : ELEKTRA_PLUGIN_END);
158 : }
159 :
|