Compare commits

...

266 Commits

Author SHA1 Message Date
TIP Automation User
3eb45c219c Chg: update image tag in helm values to v3.0.0-RC1 2023-11-27 17:38:10 +00:00
stephb9959
7d8e15bf66 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-24 21:38:48 -08:00
stephb9959
3f60c5abc6 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-24 11:31:33 -08:00
stephb9959
d85fb32af9 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 23:30:46 -08:00
stephb9959
030991f13c https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:44:43 -08:00
stephb9959
142541180f https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:41:54 -08:00
stephb9959
9bd48bf029 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:32:17 -08:00
stephb9959
8581048528 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:27:37 -08:00
stephb9959
6cfb0ae975 https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:19:17 -08:00
stephb9959
45561de44b https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 09:10:51 -08:00
stephb9959
2fccfd756e https://telecominfraproject.atlassian.net/browse/WIFI-13147
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-23 08:56:18 -08:00
stephb9959
df42837a76 https://telecominfraproject.atlassian.net/browse/WIFI-13172
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-22 21:40:38 -08:00
stephb9959
4bc1ac1aef https://telecominfraproject.atlassian.net/browse/WIFI-13172
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-22 10:09:49 -08:00
stephb9959
77ee9d48d0 https://telecominfraproject.atlassian.net/browse/WIFI-13172
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-22 09:21:31 -08:00
stephb9959
7154cca4b9 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-20 21:13:22 -08:00
stephb9959
77732bdb95 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-20 13:40:27 -08:00
stephb9959
7a8a05d77d https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-17 14:02:44 -08:00
stephb9959
aa2c28355b https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-17 13:55:31 -08:00
stephb9959
b6cb5d003b https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-17 13:54:31 -08:00
stephb9959
c93acdf54a https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-15 11:20:12 -08:00
stephb9959
0c5e0d649e https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-15 11:16:22 -08:00
stephb9959
1757440cfe https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-15 08:47:41 -08:00
stephb9959
c3ccfe455e https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-13 13:26:11 -08:00
stephb9959
66ec7745bb https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-13 13:10:26 -08:00
stephb9959
531c51dd64 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-12 23:19:05 -08:00
stephb9959
227ec2dc96 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-10 22:27:25 -08:00
stephb9959
50c5c76484 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-10 22:22:58 -08:00
stephb9959
7a567e400b https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-11-10 22:15:37 -08:00
stephb9959
148eabdbc2 https://telecominfraproject.atlassian.net/browse/WIFI-13110
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-31 07:14:59 -07:00
stephb9959
94ae20ce65 https://telecominfraproject.atlassian.net/browse/WIFI-13104
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-30 10:50:20 -07:00
stephb9959
fd80f02f0b https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 14:03:18 -07:00
stephb9959
943cdd5010 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 13:38:59 -07:00
stephb9959
36a5f4a5da https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 13:30:36 -07:00
stephb9959
e0e8cc1295 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 12:00:58 -07:00
stephb9959
d7bad290e9 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 11:57:25 -07:00
stephb9959
06766d2ed9 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 11:38:45 -07:00
stephb9959
913a3e4ce1 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-26 11:35:02 -07:00
stephb9959
4e713e4471 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-23 09:04:00 -07:00
stephb9959
cb10ea6a7f https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-23 08:34:15 -07:00
stephb9959
f5095b9f79 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:46:18 -07:00
stephb9959
8a69089513 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:42:59 -07:00
stephb9959
ba6c657587 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:33:50 -07:00
stephb9959
177deb8cd2 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:32:04 -07:00
stephb9959
1dfc478d0e https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:26:21 -07:00
stephb9959
f077fb7fad https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:23:36 -07:00
stephb9959
0dc1be1f41 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:18:28 -07:00
stephb9959
e1a0864b68 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:15:29 -07:00
stephb9959
222c796eee https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 11:12:36 -07:00
stephb9959
15fe0df04a https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 10:46:05 -07:00
stephb9959
ad1a3c694c https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 10:41:26 -07:00
stephb9959
04be75f037 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-20 07:31:38 -07:00
stephb9959
8cd26ce8cb https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 17:01:56 -07:00
stephb9959
525f53aaa9 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 16:51:15 -07:00
stephb9959
ab95733067 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 16:23:55 -07:00
stephb9959
35f4e26ca4 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 16:09:49 -07:00
stephb9959
14f63cb324 https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 11:08:48 -07:00
stephb9959
0962c8383a https://telecominfraproject.atlassian.net/browse/WIFI-12692
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-19 08:06:09 -07:00
stephb9959
891965a321 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-18 16:00:14 -07:00
stephb9959
4d2adc3c3a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-18 15:54:31 -07:00
stephb9959
24eb4079d7 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 17:09:12 -07:00
stephb9959
53010fca84 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 14:56:43 -07:00
stephb9959
6f3079ab0a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 14:52:57 -07:00
stephb9959
c73a7c6c09 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 14:40:01 -07:00
stephb9959
bb60fef3d6 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 13:57:09 -07:00
stephb9959
b52766d23a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 13:04:57 -07:00
stephb9959
6f9a9471c3 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 13:01:00 -07:00
stephb9959
992c169ac7 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 12:44:30 -07:00
stephb9959
ba8a932b36 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 12:40:21 -07:00
stephb9959
13dc97d35b https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 12:37:24 -07:00
stephb9959
0ef01e5547 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 12:32:07 -07:00
stephb9959
138b236832 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:56:05 -07:00
stephb9959
a0d4606c22 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:52:20 -07:00
stephb9959
a5200e46b7 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:41:34 -07:00
stephb9959
2d3866a987 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:38:50 -07:00
stephb9959
0251b40287 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:32:55 -07:00
stephb9959
1e2f215902 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:15:28 -07:00
stephb9959
8184027534 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:12:18 -07:00
stephb9959
a43841b867 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 11:01:51 -07:00
stephb9959
c391ea2f04 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 10:40:16 -07:00
stephb9959
111faaa80d https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-16 10:10:50 -07:00
stephb9959
687cbcd0a4 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:50:03 -07:00
stephb9959
c48665d4c5 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:43:06 -07:00
stephb9959
c873681adc https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:37:33 -07:00
stephb9959
cb64f8a809 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:35:47 -07:00
stephb9959
0d8be1fd46 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:32:58 -07:00
stephb9959
e496f71e7d https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:27:11 -07:00
stephb9959
de7c8b687a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-11 14:11:08 -07:00
stephb9959
61e346e0bf https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 12:23:55 -07:00
stephb9959
67bf9ca8c6 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 12:18:13 -07:00
stephb9959
14b7fc8a0e https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 12:11:52 -07:00
stephb9959
546d6f9ee0 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 11:55:09 -07:00
stephb9959
fe74fdecf9 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 10:45:39 -07:00
stephb9959
c53a67edd5 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 10:35:14 -07:00
stephb9959
5207f1e1a0 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 10:29:29 -07:00
stephb9959
53aa2f05d2 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 10:07:00 -07:00
stephb9959
2405b9fe95 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 10:03:04 -07:00
stephb9959
bc14bf28bf https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 09:52:15 -07:00
stephb9959
878e705db5 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 09:07:59 -07:00
stephb9959
be62022344 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 08:49:03 -07:00
stephb9959
432434a377 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-06 08:34:24 -07:00
stephb9959
60860ad9de https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-10-04 08:51:39 -07:00
stephb9959
29d6f2dda1 Merge remote-tracking branch 'origin/master' 2023-09-28 20:34:34 -07:00
stephb9959
330b4176f2 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-28 20:34:22 -07:00
Stephane Bourque
75b76bb380 https://telecominfraproject.atlassian.net/browse/WIFI-12937
Update build instructions
2023-09-25 22:02:41 -07:00
stephb9959
c48d129f4a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 21:57:28 -07:00
stephb9959
673f506ff0 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 21:44:34 -07:00
stephb9959
ac078ec1b8 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 21:38:39 -07:00
stephb9959
2007998ae1 https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 16:16:57 -07:00
stephb9959
8050228b40 https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 16:12:41 -07:00
stephb9959
a73ea9b260 https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 16:12:00 -07:00
stephb9959
334728ca4e https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 16:07:30 -07:00
stephb9959
33e010bf78 https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 16:02:51 -07:00
stephb9959
657c96f8cd https://telecominfraproject.atlassian.net/browse/WIFI-12947
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-25 15:55:47 -07:00
stephb9959
5cd421a4b9 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-24 10:52:22 -07:00
stephb9959
b5a0c96927 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-23 15:23:55 -07:00
stephb9959
e5a22a1af2 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 22:27:21 -07:00
stephb9959
4f1fa18cf6 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 13:44:33 -07:00
stephb9959
bc04d0b774 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 13:10:44 -07:00
stephb9959
598a15100d https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 13:04:28 -07:00
stephb9959
3227883074 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 12:54:03 -07:00
stephb9959
4a4c771e52 https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 12:33:45 -07:00
stephb9959
2f45a6955d https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 12:23:45 -07:00
stephb9959
78015d2ecf https://telecominfraproject.atlassian.net/browse/WIFI-12954
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-22 12:16:59 -07:00
stephb9959
9235495e2c https://telecominfraproject.atlassian.net/browse/WIFI-12945
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-19 21:54:42 -07:00
stephb9959
84e4a201e7 https://telecominfraproject.atlassian.net/browse/WIFI-12945
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-18 09:39:23 -07:00
stephb9959
89522132d0 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 15:16:05 -07:00
stephb9959
780cf3e18f https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 15:05:39 -07:00
stephb9959
6ba3c6d713 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 14:58:11 -07:00
stephb9959
eae89452ff https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 14:46:33 -07:00
stephb9959
33884c8b81 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 14:19:54 -07:00
stephb9959
1b33470d69 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 12:07:51 -07:00
stephb9959
625ace2d50 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 10:26:08 -07:00
stephb9959
09b50cde9b https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 10:20:01 -07:00
stephb9959
1c6022c227 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 10:09:19 -07:00
stephb9959
960640cc05 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 10:08:18 -07:00
stephb9959
ebc4fd6f4c https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 10:05:46 -07:00
stephb9959
2542635aa8 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 09:54:21 -07:00
stephb9959
8150daa6d5 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 09:44:08 -07:00
stephb9959
06af6eb5a1 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 09:27:15 -07:00
stephb9959
fcc765c981 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 09:22:22 -07:00
stephb9959
98db7f19d1 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-15 09:15:02 -07:00
stephb9959
904d034d5f https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:50:33 -07:00
stephb9959
52fa1ac922 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:48:31 -07:00
stephb9959
7790cde143 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:30:13 -07:00
stephb9959
1d294c86a2 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:28:08 -07:00
stephb9959
45ba1d94ba https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:18:23 -07:00
stephb9959
bdcb1aebce https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:14:06 -07:00
stephb9959
cb276b3246 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 15:12:39 -07:00
stephb9959
eeac5844f6 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 14:58:11 -07:00
stephb9959
396462c5a2 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 14:55:02 -07:00
stephb9959
b83b15d2a3 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 14:52:13 -07:00
stephb9959
1a6fb2a277 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 14:29:45 -07:00
stephb9959
c2012bcc00 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 14:27:41 -07:00
stephb9959
15f938fc07 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 07:37:11 -07:00
stephb9959
8718bb882d https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 07:32:32 -07:00
stephb9959
bc38160b71 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 07:29:22 -07:00
stephb9959
99c037b1ed https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 07:09:50 -07:00
stephb9959
c66ab909d4 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-14 07:00:14 -07:00
stephb9959
cf811a5767 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 23:59:30 -07:00
stephb9959
d7b5d7fda3 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 23:48:40 -07:00
stephb9959
797165f10d https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 23:43:38 -07:00
stephb9959
32f094562a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 13:15:23 -07:00
stephb9959
bc8f714362 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 12:19:24 -07:00
stephb9959
ec0f2ae59e https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 10:02:19 -07:00
stephb9959
8f34181ae5 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 09:18:40 -07:00
stephb9959
92f14f517a https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 08:33:40 -07:00
stephb9959
caf1ec9381 https://telecominfraproject.atlassian.net/browse/WIFI-7831
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-13 08:10:19 -07:00
stephb9959
6b49c684c5 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-09-01 09:25:51 -07:00
stephb9959
5425366f0c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 15:26:20 -07:00
stephb9959
6ea604c64f https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 15:24:07 -07:00
stephb9959
816885273d https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 13:12:08 -07:00
stephb9959
da6a49cda6 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 12:58:11 -07:00
stephb9959
0b02e0d8fd https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 12:52:34 -07:00
stephb9959
f03a5ca216 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 12:34:26 -07:00
stephb9959
cc1aac5520 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 11:56:52 -07:00
stephb9959
fb265ff767 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 10:42:51 -07:00
stephb9959
746458d6ac https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:54:27 -07:00
stephb9959
63d2bcde53 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:52:16 -07:00
stephb9959
68827af75b https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:33:11 -07:00
stephb9959
ba525dfc19 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:28:06 -07:00
stephb9959
174c0fa430 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:18:14 -07:00
stephb9959
e50392d837 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:17:20 -07:00
stephb9959
d28d70e5b9 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:09:16 -07:00
stephb9959
240950787c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:07:47 -07:00
stephb9959
e6da06e22c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 09:01:25 -07:00
stephb9959
7edbdb719c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 08:31:42 -07:00
stephb9959
992616c01b https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 08:07:15 -07:00
stephb9959
a17529d0c4 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-31 07:49:04 -07:00
stephb9959
c1d4082401 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-30 23:06:40 -07:00
stephb9959
fabea09f3d https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-30 22:53:02 -07:00
stephb9959
bb577a3fc1 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-30 22:38:29 -07:00
stephb9959
1d5007ab6a https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-30 22:33:22 -07:00
stephb9959
624f995966 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-30 08:13:01 -07:00
stephb9959
e78ed60974 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 16:23:04 -07:00
stephb9959
df769135b6 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 16:04:12 -07:00
stephb9959
8a77ba8c76 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 15:59:23 -07:00
stephb9959
d0931d95d5 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 15:50:39 -07:00
stephb9959
a4c6d26a6c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 14:27:00 -07:00
stephb9959
6b0594a393 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 14:19:40 -07:00
stephb9959
9844b8a6b8 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 14:09:06 -07:00
stephb9959
3d1887c5a8 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:58:40 -07:00
stephb9959
ed845b6a0d https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:53:57 -07:00
stephb9959
7d58000caa https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:45:22 -07:00
stephb9959
0f3c847c60 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:28:47 -07:00
stephb9959
d5bc014618 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:24:12 -07:00
stephb9959
104da1278b https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-29 13:23:07 -07:00
stephb9959
6933602706 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 21:37:09 -07:00
stephb9959
b7df12e7b0 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 20:28:28 -07:00
stephb9959
029bc8e3df https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 16:25:32 -07:00
stephb9959
ed66a2cc2b https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 16:16:03 -07:00
stephb9959
25383df599 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 13:53:18 -07:00
stephb9959
25fb62403d https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 13:41:53 -07:00
stephb9959
c928c1492b https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 13:31:55 -07:00
stephb9959
958b07b0df https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 12:56:02 -07:00
stephb9959
642c2bb914 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 12:46:02 -07:00
stephb9959
0486907e33 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 12:44:08 -07:00
stephb9959
6b92d0619c https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 12:34:26 -07:00
stephb9959
7093999c19 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 11:42:47 -07:00
stephb9959
ef2e4069d0 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-28 07:57:10 -07:00
stephb9959
3fdb6a6177 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-21 12:11:02 -07:00
stephb9959
3b9d3ee422 https://telecominfraproject.atlassian.net/browse/WIFI-12871
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-10 10:26:56 -07:00
stephb9959
a4ea9744cc https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-09 23:19:49 -07:00
stephb9959
1aa3af7cec https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-03 23:22:39 -07:00
stephb9959
10cced8d5e https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-03 22:26:18 -07:00
stephb9959
de85d4e517 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-03 11:08:47 -07:00
stephb9959
a06a6a2b27 https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-03 10:34:40 -07:00
stephb9959
1a4af66a8a https://telecominfraproject.atlassian.net/browse/WIFI-12868
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-08-03 10:12:45 -07:00
stephb9959
6db4feeedd https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 15:25:40 -07:00
stephb9959
dfdfd06ab1 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 15:18:10 -07:00
stephb9959
842995f7f6 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 14:57:11 -07:00
stephb9959
ba01cfa02b https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 14:14:53 -07:00
stephb9959
329dfbbcde https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 12:24:06 -07:00
stephb9959
ac1b5df59a https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 12:11:48 -07:00
stephb9959
8f2dd3ec6e https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 11:57:46 -07:00
stephb9959
8edf3af709 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 11:54:02 -07:00
stephb9959
4392b37c0b https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 11:49:01 -07:00
stephb9959
286607fc5d https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 10:08:47 -07:00
stephb9959
4f15fb055d https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 10:04:45 -07:00
stephb9959
3864082269 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 10:02:04 -07:00
stephb9959
076ad66754 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:57:15 -07:00
stephb9959
cd5d8365fb https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:52:47 -07:00
stephb9959
1b4ba18d70 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:45:43 -07:00
stephb9959
80502c7414 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:42:08 -07:00
stephb9959
dea0e371fd https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:38:26 -07:00
stephb9959
df9c11b640 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:32:22 -07:00
stephb9959
fef2e00fef https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:28:28 -07:00
stephb9959
9f27ed2d64 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:26:17 -07:00
stephb9959
a9ebb18609 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:19:16 -07:00
stephb9959
7b2d557d90 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:15:31 -07:00
stephb9959
fe50bdc8c5 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:12:42 -07:00
stephb9959
3ae4676df2 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:09:25 -07:00
stephb9959
ff78235bf7 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 09:04:30 -07:00
stephb9959
68d11560ee https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 08:59:22 -07:00
stephb9959
b468952e04 https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 08:38:41 -07:00
stephb9959
aec6e6f71d https://telecominfraproject.atlassian.net/browse/WIFI-12762
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-18 08:32:15 -07:00
stephb9959
1020473e54 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-13 06:57:43 -07:00
stephb9959
3433a13b62 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 14:51:50 -07:00
stephb9959
b9ecb8632a https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 13:25:41 -07:00
stephb9959
be97cca949 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 09:11:47 -07:00
stephb9959
0c46a0a957 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 09:07:18 -07:00
stephb9959
3e0d091f4d https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 08:45:27 -07:00
stephb9959
1387c67219 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 08:31:03 -07:00
stephb9959
fd02712159 https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-12 07:31:33 -07:00
stephb9959
c75689800e https://telecominfraproject.atlassian.net/browse/WIFI-12691
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-11 23:15:00 -07:00
stephb9959
b094709d4c https://telecominfraproject.atlassian.net/browse/WIFI-12738
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-10 13:17:58 -07:00
stephb9959
f1a6f42b8a https://telecominfraproject.atlassian.net/browse/WIFI-12738
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-07-10 11:06:27 -07:00
83 changed files with 5491 additions and 2365 deletions

2
.idea/ucentral.iml generated
View File

@@ -2,7 +2,7 @@
<module classpath="CMake" type="CPP_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python facet">
<configuration sdkName="Python 3.9 (venv)" />
<configuration sdkName="Python 3.9 (wlan-cloud-ucentralgw)" />
</facet>
</component>
</module>

View File

@@ -24,7 +24,7 @@ sudo apt install librdkafka-dev // default-libmysqlclient-dev
sudo apt install nlohmann-json-dev
cd ~
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
cd poco
mkdir cmake-build
cd cmake-build
@@ -75,7 +75,7 @@ sudo yum install yaml-cpp-devel lua-devel
sudo dnf install postgresql.x86_64 librdkafka-devel
sudo dnf install postgresql-devel json-devel
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
cd poco
mkdir cmake-build
cd cmake-build
@@ -125,7 +125,7 @@ brew install openssl \
nlohmann-json \
fmt
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
pushd poco
mkdir cmake-build
push cmake-build

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 2.10.0)
project(owgw VERSION 3.0.0)
set(CMAKE_CXX_STANDARD 17)
@@ -49,7 +49,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1" -DBOOST_NO_CXX98_FUNCTION_BASE=1)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
@@ -199,7 +199,7 @@ add_executable( owgw
src/AP_WS_Process_deviceupdate.cpp
src/AP_WS_Process_telemetry.cpp
src/AP_WS_Process_venuebroadcast.cpp
src/RADSEC_server.h
src/RADIUS_Destination.h
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
src/framework/RESTAPI_SystemConfiguration.h
src/ScriptManager.cpp src/ScriptManager.h
@@ -211,7 +211,7 @@ add_executable( owgw
src/RegulatoryInfo.cpp src/RegulatoryInfo.h
src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h)
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h)
if(NOT SMALL_BUILD)
@@ -223,14 +223,17 @@ INSTALL(TARGETS owgw
target_link_libraries(owgw PUBLIC
${Poco_LIBRARIES}
${ZLIB_LIBRARIES})
${ZLIB_LIBRARIES}
)
if(NOT SMALL_BUILD)
target_link_libraries(owgw PUBLIC
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
CppKafka::cppkafka
fmt::fmt
)
${MySQL_LIBRARIES}
${ZLIB_LIBRARIES}
CppKafka::cppkafka
fmt::fmt
resolv
)
if(UNIX AND NOT APPLE)
target_link_libraries(owgw PUBLIC PocoJSON)
endif()

View File

@@ -2,6 +2,8 @@ ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v2
ARG CPPKAFKA_VERSION=tip-v1
ARG VALIJASON_VERSION=tip-v1
ARG APP_NAME=owgw
ARG APP_HOME_DIR=/openwifi
FROM debian:$DEBIAN_VERSION AS build-base
@@ -53,12 +55,14 @@ RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS owgw-build
FROM build-base AS app-build
ADD CMakeLists.txt build /owgw/
ADD cmake /owgw/cmake
ADD src /owgw/src
ADD .git /owgw/.git
ARG APP_NAME
ADD CMakeLists.txt build /${APP_NAME}/
ADD cmake /${APP_NAME}/cmake
ADD src /${APP_NAME}/src
ADD .git /${APP_NAME}/.git
COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib
@@ -66,23 +70,33 @@ COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=valijson-build /usr/local/include /usr/local/include
WORKDIR /owgw
WORKDIR /${APP_NAME}
RUN mkdir cmake-build
WORKDIR /owgw/cmake-build
WORKDIR /${APP_NAME}/cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
FROM debian:$DEBIAN_VERSION
ENV OWGW_USER=owgw \
OWGW_ROOT=/owgw-data \
OWGW_CONFIG=/owgw-data
ARG APP_NAME
ARG APP_HOME_DIR
RUN useradd "$OWGW_USER"
ENV APP_NAME=$APP_NAME \
APP_USER=$APP_NAME \
APP_ROOT=/$APP_NAME-data \
APP_CONFIG=/$APP_NAME-data \
APP_HOME_DIR=$APP_HOME_DIR
RUN mkdir /openwifi
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
# This is for legacy
ENV OWGW_USER=$APP_USER \
OWGW_ROOT=$APP_ROOT \
OWGW_CONFIG=$APP_CONFIG
RUN useradd $APP_USER
RUN mkdir $APP_HOME_DIR
RUN mkdir -p $APP_ROOT $APP_CONFIG && \
chown $APP_USER: $APP_ROOT $APP_CONFIG
RUN apt-get update && apt-get install --no-install-recommends -y \
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
@@ -91,14 +105,14 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
COPY owgw.properties.tmpl /
COPY $APP_NAME.properties.tmpl /
COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
COPY rtty_ui /dist/rtty_ui
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
COPY --from=owgw-build /owgw/cmake-build/owgw /openwifi/owgw
COPY --from=app-build /$APP_NAME/cmake-build/$APP_NAME $APP_HOME_DIR/$APP_NAME
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib/
@@ -107,4 +121,4 @@ RUN ldconfig
EXPOSE 15002 16002 16003 17002 16102
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/openwifi/owgw"]
CMD ${APP_HOME_DIR}/${APP_NAME}

View File

@@ -775,6 +775,146 @@ The device should answer:
}
```
#### Controller wants the device to replace its certificates
Controller sends this command to run a predefined script. Extreme care must be taken.
```json
{ "jsonrpc" : "2.0" ,
"method" : "certupdate" ,
"params" : {
"serial" : <serial number>,
"certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
#### Controller wants the device to switch to another controller
Controller sends this when the device should change the controller it connects to without looking up a new redirector.
```json
{ "jsonrpc" : "2.0" ,
"method" : "transfer" ,
"params" : {
"serial" : <serial number>,
"server" : <controller hostname>,
"port" : <controller port number (integer)>,
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
### RRM AP device commands
The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the
controller will not or cannot verify if they have been sent or the action was performed.
```json
{ "jsonrpc" : "2.0" ,
"method" : "rrm" ,
"params" : {
"serial" : <serial number>,
"actions" : [ array of actions. Each possible action is defined next]
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
#### RRM Roam action
##### Kick
```json
{
"action" : "kick" ,
"addr" : <mac if the client that shall be kicked> ,
"reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
"ban_time": <number> (seconds, optional)
}
```
##### Channel Switch Announcement
```json
{
"action" : "channel_switch" ,
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
"channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
}
```
##### Change TX-Power
```json
{
"action" : "tx_power" ,
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
"level" : <number> (DBm inside the positive number space)
}
```
##### Beacon Scan
```json
{
"action" : "beacon_request" ,
"addr" : <mac if the client that shall perform the scan> ,
"ssid": <string>, (the SSID the client shall scan for on all frequencies),
"channel": <number> (the channel that shall be scanned)
}
```
##### BSS Transition
```json
{
"action" : "bss_transition" ,
"addr" : <mac if the client that shall perform the roam> ,
"neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
}
```
##### Update neighbours
```json
{
"action" : "neighbors" ,
"bssid" : <mac of the SSID> , (the SSID of the specific VAP)
"neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
}
```
### `rtty server`
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.

2
build
View File

@@ -1 +1 @@
64
10

View File

@@ -6,35 +6,35 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\${APP_ROOT}/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\${APP_ROOT}/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\${APP_ROOT}/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\${APP_ROOT}/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\${APP_ROOT}/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\${APP_ROOT}/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
@@ -51,7 +51,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
RTTY_TOKEN=${RTTY_TOKEN:-""} \
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
RTTY_ASSETS=${RTTY_ASSETS:-"\${APP_ROOT}/rtty_ui"} \
RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
@@ -64,41 +64,41 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"${APP_USER}"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"${APP_USER}"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"${APP_NAME}"} \
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"${APP_USER}"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"${APP_USER}"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"${APP_NAME}"} \
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
fi
# Check if rtty_ui directory exists
export RTTY_ASSETS=$(grep 'rtty.assets' $OWGW_CONFIG/owgw.properties | awk -F '=' '{print $2}' | xargs | envsubst)
export RTTY_ASSETS=$(grep 'rtty.assets' "${APP_CONFIG}"/"${APP_NAME}".properties | awk -F '=' '{print $2}' | xargs | envsubst)
if [ -z "$RTTY_ASSETS" ]; then
export RTTY_ASSETS="$OWGW_ROOT/rtty_ui"
export RTTY_ASSETS="${APP_ROOT}/rtty_ui"
fi
if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
mkdir -p $(dirname $RTTY_ASSETS)
mkdir -p "$(dirname $RTTY_ASSETS)"
fi
if [[ ! -d "$RTTY_ASSETS" ]]; then
cp -r /dist/rtty_ui $RTTY_ASSETS
fi
if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
if [ "$1" = "${APP_HOME_DIR}/${APP_NAME}" -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
chown -R "$APP_USER": "${APP_ROOT}" "$APP_CONFIG"
fi
exec gosu "$OWGW_USER" "$@"
exec gosu "$APP_USER" "$@"
fi
exec "$@"

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images:
owgw:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
tag: master
tag: v3.0.0-RC1
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: uCentral gateway API
description: A process to manage configuration for devices.
version: 2.10.0
version: 2.11.0
license:
name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -553,6 +553,35 @@ components:
items:
$ref : '#/components/schemas/DefaultConfiguration'
DefaultFirmware:
type: object
properties:
deviceType:
type: string
description:
type: string
uri:
type: string
revision:
type: string
imageCreationDate:
type: integer
format: int64
created:
type: integer
format: int64
lastModified:
type: integer
format: int64
DefaultFirmwareList:
type: object
properties:
firmwares:
type: array
items:
$ref: '#/components/schemas/DefaultFirmware'
UpgradeRequest:
type: object
properties:
@@ -874,6 +903,114 @@ components:
kafkaClients:
type: integer
RRM_Kick:
type: object
properties:
action:
type: string
enum:
- kick
addr:
type: string
format: mac
reason:
type: integer
default: 5
ban_time:
type: integer
format: int64
RRM_channel_switch:
type: object
properties:
action:
type: string
enum:
- channel_switch
bssid:
type: string
format: mac
channel:
type: integer
RRM_tx_power:
type: object
properties:
action:
type: string
enum:
- tx_power
bssid:
type: string
format: mac
level:
type: integer
RRM_beacon_request:
type: object
properties:
action:
type: string
enum:
- beacon_request
addr:
type: string
format: mac
ssid:
type: string
channel:
type: integer
RRM_bss_transition:
type: object
properties:
action:
type: string
enum:
- bss_transition
addr:
type: string
format: mac
neighbors:
type: array
items:
type: string
format: mac
RRM_neighbors:
type: object
properties:
action:
type: string
enum:
- neighbors
bssid:
type: string
format: mac
neighbors:
type: array
items:
type: string
format: mac
RRM_action:
type: object
oneOf:
- $ref: '#/components/schemas/RRM_Kick'
- $ref: '#/components/schemas/RRM_channel_switch'
- $ref: '#/components/schemas/RRM_tx_power'
- $ref: '#/components/schemas/RRM_beacon_request'
- $ref: '#/components/schemas/RRM_bss_transition'
- $ref: '#/components/schemas/RRM_neighbors'
RRM_actions:
type: object
properties:
actions:
type: array
items:
$ref: '#/components/schemas/RRM_action'
#########################################################################################
##
## These are endpoints that all services in the uCentral stack must provide
@@ -942,12 +1079,6 @@ components:
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
SystemCommandResults:
type: object
oneOf:
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
NoteInfo:
type: object
properties:
@@ -987,6 +1118,33 @@ components:
type: integer
format: int64
SystemResources:
type: object
properties:
numberOfFileDescriptors:
type: integer
format: int64
currRealMem:
type: integer
format: int64
peakRealMem:
type: integer
format: int64
currVirtMem:
type: integer
format: int64
peakVirtMem:
type: integer
format: int64
SystemCommandResults:
type: object
oneOf:
- $ref: '#/components/schemas/SystemResources'
- $ref: '#/components/schemas/SystemInfoResults'
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
SystemCommandSetLogLevel:
type: object
properties:
@@ -1289,6 +1447,30 @@ components:
$ref: '#/components/schemas/RadiusProxyServerConfig'
coaConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
radsecPoolType:
type: string
enum:
- generic
- orion
- globalreach
- radsec
default:
generic
poolProxyIp:
type: string
description: This is the fake IP for the entire pool
example:
- These addresses must match the addresses in the AP configuration and must start with 0.0
- 0.0.0.1
- 0.0.1.1
radsecPoolKeepAlive:
type: integer
description: The keep alive value in seconds. Usually 30s or less.
format: int64
default: 25
enabled:
type: boolean
default: true
RadiusProxyPoolList:
type: object
@@ -1358,6 +1540,31 @@ components:
type: string
chargeableUserIdentity:
type: string
userName:
type: string
DeviceTransferRequest:
type: object
properties:
serialNumber:
type: string
format: uuid
server:
type: string
format: hostname
port:
type: integer
format: int32
DeviceCertificateUpdateRequest:
type: object
properties:
serialNumber:
type: string
encodedCertificate:
type: string
format: base64
description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
paths:
/devices:
@@ -1505,8 +1712,12 @@ paths:
type: integer
format: int64
required: false
- in: query
description: Filter the results
name: simulatedDevices
schema:
type: boolean
required: false
responses:
200:
$ref: '#/components/responses/Success'
@@ -1771,6 +1982,123 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/default_firmwares:
get:
tags:
- Firmware
summary: Retrieve the lists of all default firmwares.
description: Retrieve the lists of all default firmwares.
operationId: getDefaultFirmwares
responses:
200:
description: List of default firmwares
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmwareList'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/default_firmware/{deviceType}:
get:
tags:
- Firmware
summary: Retrieve a default firmware.
description: Retrieve a default firmware.
operationId: getDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
responses:
200:
description: Default firmware included
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
post:
tags:
- Firmware
summary: Create a default firmware.
description: Create a default firmware.
operationId: createDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
requestBody:
description: Information used to create the new firmware entry
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Firmware
summary: Delete a default default firmware
description: Delete a default default firmware
operationId: deleteDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Firmware
summary: Update a default firmware
description: Update a default firmware
operationId: updateDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
requestBody:
description: Firmware details
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}:
get:
tags:
@@ -2382,7 +2710,7 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/:
/device/{serialNumber}/script:
post:
tags:
- Commands
@@ -2596,6 +2924,88 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/rrm:
post:
tags:
- Commands
summary: Send RRM commands to a device.
operationId: sendRRMcommandsForADevice
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Commands to send
content:
application/json:
schema:
$ref: '#/components/schemas/RRM_actions'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/transfer:
post:
tags:
- Commands
summary: Transfer a device to a new redirector.
operationId: transferDevice
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Transfer details
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DeviceTransferRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/certupdate:
post:
tags:
- Commands
summary: Update the certificates for a device.
operationId: updateCertificates
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Certificate update details
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DeviceCertificateUpdateRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/ouis:
get:
tags:
@@ -3086,6 +3496,7 @@ paths:
type: string
enum:
- coadm
- disconnectUser
requestBody:
description: operationParameters
content:
@@ -3101,8 +3512,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/deviceDashboard:
get:
tags:
@@ -3199,16 +3608,12 @@ paths:
type: string
enum:
- info
- extraConfiguration
- resources
required: true
responses:
200:
description: Successful command execution
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/SystemInfoResults'
$ref: '#/components/schemas/SystemCommandResults'
403:
$ref: '#/components/responses/Unauthorized'
404:

View File

@@ -73,6 +73,7 @@ namespace OpenWifi {
*this, &AP_WS_Connection::OnSocketError));
Registered_ = true;
Valid_ = true;
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
}
bool AP_WS_Connection::ValidatedDevice() {
@@ -141,6 +142,7 @@ namespace OpenWifi {
if(AP_WS_Server::IsSim(CN_)) {
State_.VerifiedCertificate = GWObjects::SIMULATED;
Simulated_ = true;
}
std::string reason, author;
@@ -222,17 +224,15 @@ namespace OpenWifi {
return false;
}
static void NotifyKafkaDisconnect(const std::string &SerialNumber) {
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
try {
Poco::JSON::Object Disconnect;
Poco::JSON::Object Details;
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
Details.set(uCentralProtocol::UUID,uuid);
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(Disconnect, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
} catch (...) {
}
}
@@ -242,9 +242,9 @@ namespace OpenWifi {
EndConnection();
}
void DeviceDisconnectionCleanup(const std::string &SerialNumber) {
void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
if (KafkaManager()->Enabled()) {
NotifyKafkaDisconnect(SerialNumber);
NotifyKafkaDisconnect(SerialNumber, uuid);
}
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
}
@@ -272,7 +272,7 @@ namespace OpenWifi {
WS_->close();
if(!SerialNumber_.empty()) {
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_);
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_);
Cleanup.detach();
}
@@ -720,12 +720,11 @@ namespace OpenWifi {
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
PingDetails.set(uCentralProtocol::UUID, uuid_);
PingDetails.set("locale", State_.locale);
PingObject.set(uCentralProtocol::PING, PingDetails);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(PingObject, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
}
return;
} break;
@@ -954,23 +953,22 @@ namespace OpenWifi {
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
if (Doc->has(uCentralProtocol::RADIUSDATA)) {
std::string secret;
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
if (Type == uCentralProtocol::RADIUSACCT) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendAccountingData(SerialNumber_, DecodedData.c_str(),
DecodedData.size(),secret);
DecodedData.size());
} else if (Type == uCentralProtocol::RADIUSAUTH) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_, DecodedData.c_str(),
DecodedData.size(), secret);
DecodedData.size());
} else if (Type == uCentralProtocol::RADIUSCOA) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendCoAData(SerialNumber_, DecodedData.c_str(),
DecodedData.size(), secret);
DecodedData.size());
}
}
}

View File

@@ -4,7 +4,7 @@
#pragma once
#include <shared_mutex>
#include <mutex>
#include <string>
#include "Poco/JSON/Object.h"
@@ -59,12 +59,12 @@ namespace OpenWifi {
bool StopKafkaTelemetry(uint64_t RPCID);
inline void GetLastStats(std::string &LastStats) {
std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
LastStats = RawLastStats_;
}
inline void SetLastStats(const std::string &LastStats) {
std::unique_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
RawLastStats_ = LastStats;
try {
Poco::JSON::Parser P;
@@ -96,24 +96,24 @@ namespace OpenWifi {
}
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
std::unique_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
RawLastHealthcheck_ = H;
}
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
H = RawLastHealthcheck_;
}
inline void GetState(GWObjects::ConnectionState &State) const {
std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
State = State_;
}
inline bool HasGPS() { return hasGPS; }
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
R = Restrictions_;
}
@@ -154,15 +154,15 @@ namespace OpenWifi {
friend class AP_WS_Server;
inline GWObjects::DeviceRestrictions Restrictions() const {
std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_);
return Restrictions_;
}
inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
private:
mutable std::shared_mutex ConnectionMutex_;
std::shared_mutex TelemetryMutex_;
mutable std::mutex ConnectionMutex_;
std::mutex TelemetryMutex_;
Poco::Logger &Logger_;
Poco::Net::SocketReactor &Reactor_;
std::unique_ptr<Poco::Net::WebSocket> WS_;
@@ -201,6 +201,8 @@ namespace OpenWifi {
void UpdateCounts();
bool hasGPS=false;
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
std::uint64_t uuid_=0;
bool Simulated_=false;
};
} // namespace OpenWifi

View File

@@ -21,11 +21,7 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) {
auto Data = ParamsObj->get(uCentralProtocol::DATA);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, *ParamsObj);
}
}
}

View File

@@ -14,6 +14,8 @@
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "firmware_revision_cache.h"
#include "UI_GW_WebSocketNotifications.h"
#include <GWKafkaEvents.h>
@@ -30,9 +32,7 @@ namespace OpenWifi {
Event.set("type", "device.firmware_change");
Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
}
}
@@ -49,9 +49,7 @@ namespace OpenWifi {
Event.set("type", "device.not_provisioned");
Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
}
}
@@ -63,6 +61,11 @@ namespace OpenWifi {
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
std::string DevicePassword;
if(ParamsObj->has("password")) {
DevicePassword = ParamsObj->get("password").toString();
}
SerialNumber_ = Serial;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
@@ -109,7 +112,55 @@ namespace OpenWifi {
GWObjects::Device DeviceInfo;
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) {
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_, State_.VerifiedCertificate==GWObjects::SIMULATED );
// check the firmware version. if this is too old, we cannot let that device connect yet, we must
// force a firmware upgrade
GWObjects::DefaultFirmware MinimumFirmware;
if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
/*
{ "jsonrpc" : "2.0" ,
"method" : "upgrade" ,
"params" : {
"serial" : <serial number> ,
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
"uri" : <URI to download the firmware>,
"FWsignature" : <string representation of the signature for the FW> (optional)
},
"id" : <some number>
}
*/
Poco::JSON::Object UpgradeCommand, Params;
UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE);
Params.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
Params.set(uCentralProtocol::WHEN, 0);
Params.set(uCentralProtocol::URI, MinimumFirmware.uri);
Params.set(uCentralProtocol::KEEP_REDIRECTOR,1);
UpgradeCommand.set(uCentralProtocol::PARAMS, Params);
UpgradeCommand.set(uCentralProtocol::ID, 1);
std::ostringstream Command;
UpgradeCommand.stringify(Command);
if(Send(Command.str())) {
poco_information(
Logger(),
fmt::format(
"Forcing device {} to upgrade to {} before connection is allowed.",
SerialNumber_, MinimumFirmware.revision));
} else {
poco_error(
Logger(),
fmt::format(
"Could not force device {} to upgrade to {} before connection is allowed.",
SerialNumber_, MinimumFirmware.revision));
}
return;
} else {
StorageService()->CreateDefaultDevice(
SerialNumber_, Caps, Firmware, PeerAddress_,
State_.VerifiedCertificate == GWObjects::SIMULATED);
}
} else if (!Daemon()->AutoProvisioning() && !DeviceExists) {
SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_);
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
@@ -135,6 +186,17 @@ namespace OpenWifi {
}
}
if(ParamsObj->has("reason")) {
State_.connectReason = ParamsObj->get("reason").toString();
DeviceInfo.connectReason = State_.connectReason;
++Updated;
}
if(DeviceInfo.DevicePassword!=DevicePassword) {
DeviceInfo.DevicePassword = DevicePassword.empty() ? "openwifi" : DevicePassword ;
++Updated;
}
if (DeviceInfo.lastRecordedContact==0) {
DeviceInfo.lastRecordedContact = Utils::Now();
++Updated;
@@ -170,13 +232,20 @@ namespace OpenWifi {
++Updated;
}
if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
++Updated;
}
if (Updated) {
StorageService()->UpdateDevice(DeviceInfo);
}
uint64_t UpgradedUUID = 0;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
if(!Simulated_) {
uint64_t UpgradedUUID = 0;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
}
State_.Compatible = Compatible_;
@@ -225,14 +294,11 @@ namespace OpenWifi {
GWWebSocketNotifications::DeviceConnected(Notification);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
ParamsObj->set("locale", State_.locale);
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
ParamsObj->set(uCentralProtocol::UUID, uuid_);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, *ParamsObj);
}
} else {
poco_warning(

View File

@@ -24,7 +24,7 @@ namespace OpenWifi {
StorageService()->SetDevicePassword(Serial, Password);
poco_trace(
Logger_,
fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial));
}
}

View File

@@ -34,11 +34,13 @@ namespace OpenWifi {
FullEvent.set("type", EventType);
FullEvent.set("timestamp", EventTimeStamp);
FullEvent.set("payload", EventPayload);
std::ostringstream OS;
FullEvent.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
std::make_shared<std::string>(OS.str()));
if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_,
FullEvent);
} else {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
FullEvent);
}
}
}
} catch (const Poco::Exception &E) {

View File

@@ -40,10 +40,6 @@ namespace OpenWifi {
CId_, UUID, request_uuid));
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
GWObjects::HealthCheck Check;
Check.SerialNumber = SerialNumber_;
@@ -60,11 +56,7 @@ namespace OpenWifi {
SetLastHealthCheck(Check);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
ParamsObj->set("timestamp", Utils::Now());
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj);
}
} else {
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));

View File

@@ -39,9 +39,11 @@ namespace OpenWifi {
UUID, request_uuid));
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
if(!Simulated_) {
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
SetLastStats(StateStr);
GWObjects::Statistics Stats{
@@ -56,10 +58,7 @@ namespace OpenWifi {
State_.Associations_5G, State_.Associations_6G);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj);
}
GWWebSocketNotifications::SingleDevice_t N;

View File

@@ -27,7 +27,7 @@ namespace OpenWifi {
std::ostringstream SS;
Payload->stringify(SS);
auto now = Utils::Now();
auto KafkaPayload = std::make_shared<std::string>(SS.str());
auto KafkaPayload = SS.str();
if (ParamsObj->has("adhoc")) {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
KafkaPayload);
@@ -39,7 +39,7 @@ namespace OpenWifi {
// std::endl;
TelemetryWebSocketPackets_++;
State_.websocketPackets = TelemetryWebSocketPackets_;
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, *KafkaPayload);
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload);
} else {
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
}

View File

@@ -21,11 +21,7 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) {
auto Data = ParamsObj->get(uCentralProtocol::DATA);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, *ParamsObj);
}
}
}

View File

@@ -4,7 +4,7 @@
#pragma once
#include <shared_mutex>
#include <mutex>
#include <string>
#include "Poco/Environment.h"
@@ -16,7 +16,7 @@ namespace OpenWifi {
class AP_WS_ReactorThreadPool {
public:
explicit AP_WS_ReactorThreadPool() {
NumberOfThreads_ = Poco::Environment::processorCount() * 2;
NumberOfThreads_ = Poco::Environment::processorCount() * 4;
if (NumberOfThreads_ == 0)
NumberOfThreads_ = 4;
}
@@ -46,14 +46,14 @@ namespace OpenWifi {
}
Poco::Net::SocketReactor &NextReactor() {
std::shared_lock Lock(Mutex_);
std::lock_guard Lock(Mutex_);
NextReactor_++;
NextReactor_ %= NumberOfThreads_;
return *Reactors_[NextReactor_];
}
private:
std::shared_mutex Mutex_;
std::mutex Mutex_;
uint64_t NumberOfThreads_;
uint64_t NextReactor_ = 0;
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;

View File

@@ -107,7 +107,6 @@ namespace OpenWifi {
Context->flushSessionCache();
Context->enableSessionCache(true);
Context->enableExtendedCertificateVerification(false);
// Context->disableStatelessSessionResumption();
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
Poco::Net::Context::PROTO_TLSV1_1);
@@ -172,43 +171,73 @@ namespace OpenWifi {
}
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
static uint64_t last_log = Utils::Now();
static uint64_t last_log = Utils::Now(), last_zombie_run = 0;
auto now = Utils::Now();
{
std::lock_guard Lock(WSServerMutex_);
if (!Garbage_.empty()) {
Garbage_.clear();
}
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
uint64_t total_connected_time = 0;
auto hint = SerialNumbers_.begin();
while (hint != end(SerialNumbers_)) {
if (hint->second.second == nullptr) {
hint = SerialNumbers_.erase(hint);
} else if ((now - hint->second.second->State_.LastContact) > SessionTimeOut_) {
hint->second.second->EndConnection(false);
poco_information(Logger(),fmt::format("{}: Session seems idle. Controller disconnecting device.", hint->second.second->SerialNumber_));
Sessions_.erase(hint->second.second->State_.sessionId);
Garbage_.push_back(hint->second.second);
hint = SerialNumbers_.erase(hint);
} else if (hint->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - hint->second.second->State_.started);
hint++;
} else {
NumberOfConnectingDevices_++;
hint++;
{
std::lock_guard SessionLock(SessionMutex_);
if (!Garbage_.empty()) {
Garbage_.clear();
}
}
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
? total_connected_time / NumberOfConnectedDevices_
: 0;
uint64_t total_connected_time = 0;
if(now-last_zombie_run > 20) {
poco_information(Logger(), fmt::format("Garbage collecting..."));
std::vector<std::uint64_t> SessionsToRemove;
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
last_zombie_run = now;
for(int hashIndex=0;hashIndex<256;hashIndex++) {
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto hint = SerialNumbers_[hashIndex].begin();
while (hint != end(SerialNumbers_[hashIndex])) {
if (hint->second.second == nullptr) {
hint = SerialNumbers_[hashIndex].erase(hint);
} else if ((now - hint->second.second->State_.LastContact) >
SessionTimeOut_) {
hint->second.second->EndConnection(false);
poco_information(
Logger(),
fmt::format(
"{}: Session seems idle. Controller disconnecting device.",
hint->second.second->SerialNumber_));
SessionsToRemove.emplace_back(hint->second.first);
Garbage_.push_back(hint->second.second);
hint = SerialNumbers_[hashIndex].erase(hint);
} else if (hint->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - hint->second.second->State_.started);
hint++;
} else {
NumberOfConnectingDevices_++;
hint++;
}
}
}
if(SessionsToRemove.empty()) {
poco_information(Logger(), fmt::format("Removing {} sessions.", SessionsToRemove.size()));
std::lock_guard Lock(SessionMutex_);
for (const auto &Session : SessionsToRemove) {
Sessions_.erase(Session);
}
}
AverageDeviceConnectionTime_ =
NumberOfConnectedDevices_ > 0 ? total_connected_time / NumberOfConnectedDevices_
: 0;
poco_information(Logger(), fmt::format("Garbage collecting done..."));
} else {
std::lock_guard SessionLock(SessionMutex_);
NumberOfConnectedDevices_ = Sessions_.size();
AverageDeviceConnectionTime_ += 10;
}
if ((now - last_log) > 120) {
last_log = now;
poco_information(Logger(),
@@ -233,10 +262,7 @@ namespace OpenWifi {
FullEvent.set("timestamp", now);
FullEvent.set("payload", KafkaNotification);
std::ostringstream OS;
FullEvent.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system",
std::make_shared<std::string>(OS.str()));
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
}
void AP_WS_Server::Stop() {
@@ -255,106 +281,78 @@ namespace OpenWifi {
}
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
}
DevicePtr->GetLastStats(Statistics);
Device->second.second->GetLastStats(Statistics);
return true;
}
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
}
DevicePtr->GetState(State);
Device->second.second->GetState(State);
return true;
}
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
GWObjects::HealthCheck &CheckData) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
}
DevicePtr->GetLastHealthCheck(CheckData);
Device->second.second->GetLastHealthCheck(CheckData);
return true;
}
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
std::lock_guard Lock(WSServerMutex_);
std::lock_guard SessionLock(SessionMutex_);
auto Conn = Sessions_.find(connection_id);
if (Conn == end(Sessions_))
return;
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
if ((CurrentSerialNumber == SerialNumbers_.end()) ||
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto CurrentSerialNumber = SerialNumbers_[hashIndex].find(SerialNumber);
if ((CurrentSerialNumber == SerialNumbers_[hashIndex].end()) ||
(CurrentSerialNumber->second.first < connection_id)) {
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
SerialNumbers_[hashIndex][SerialNumber] = std::make_pair(connection_id, Conn->second);
return;
}
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
std::lock_guard G(WSServerMutex_);
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
std::lock_guard SessionLock(SessionMutex_);
auto Session = Sessions_.find(session_id);
if (Session == end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto Device = SerialNumbers_.find(serial_number);
if (Device == end(SerialNumbers_)) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex])) {
Sessions_.erase(Session);
return false;
}
if (Device->second.first == session_id) {
Sessions_.erase(Session);
SerialNumbers_.erase(Device);
return true;
}
Sessions_.erase(Session);
return false;
}
bool AP_WS_Server::EndSessionUnSafe(uint64_t session_id, uint64_t serial_number) {
auto Session = Sessions_.find(session_id);
if (Session == end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto Device = SerialNumbers_.find(serial_number);
if (Device == end(SerialNumbers_)) {
Sessions_.erase(Session);
return false;
}
if (Device->second.first == session_id) {
Sessions_.erase(Session);
SerialNumbers_.erase(Device);
SerialNumbers_[hashIndex].erase(Device);
return true;
}
@@ -365,44 +363,36 @@ namespace OpenWifi {
bool AP_WS_Server::Connected(uint64_t SerialNumber,
GWObjects::DeviceRestrictions &Restrictions) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
DevicePtr->GetRestrictions(Restrictions);
return DevicePtr->State_.Connected;
Device->second.second->GetRestrictions(Restrictions);
return Device->second.second->State_.Connected;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
return DevicePtr->State_.Connected;
return Device->second.second->State_.Connected;
}
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
try {
return DevicePtr->Send(Payload);
return Device->second.second->Send(Payload);
} catch (...) {
poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
Utils::IntToSerialNumber(SerialNumber)));
@@ -411,61 +401,48 @@ namespace OpenWifi {
}
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
}
DevicePtr->StopWebSocketTelemetry(RPCID);
Device->second.second->StopWebSocketTelemetry(RPCID);
}
void
AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
}
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
}
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
}
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
}
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
}
DevicePtr->StopKafkaTelemetry(RPCID);
Device->second.second->StopKafkaTelemetry(RPCID);
}
void AP_WS_Server::GetTelemetryParameters(
@@ -473,16 +450,15 @@ namespace OpenWifi {
uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
}
DevicePtr->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
Device->second.second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
TelemetryWebSocketTimer, TelemetryKafkaTimer,
TelemetryWebSocketCount, TelemetryKafkaCount,
TelemetryWebSocketPackets, TelemetryKafkaPackets);
@@ -490,18 +466,17 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
try {
return DevicePtr->SendRadiusAccountingData(buffer, size);
return Device->second.second->SendRadiusAccountingData(buffer, size);
} catch (...) {
poco_debug(
Logger(),
@@ -513,18 +488,16 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
try {
return DevicePtr->SendRadiusAuthenticationData(buffer, size);
return Device->second.second->SendRadiusAuthenticationData(buffer, size);
} catch (...) {
poco_debug(
Logger(),
@@ -536,18 +509,16 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
}
try {
return DevicePtr->SendRadiusCoAData(buffer, size);
return Device->second.second->SendRadiusCoAData(buffer, size);
} catch (...) {
poco_debug(Logger(),
fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",

View File

@@ -75,7 +75,6 @@ namespace OpenWifi {
bool IsCertOk() { return IssuerCert_ != nullptr; }
bool ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate);
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
return IsSim(Poco::toLower(SerialNumber)) &&
@@ -102,24 +101,16 @@ namespace OpenWifi {
inline void AddConnection(uint64_t session_id,
std::shared_ptr<AP_WS_Connection> Connection) {
std::lock_guard Lock(WSServerMutex_);
std::lock_guard Lock(SessionMutex_);
Sessions_[session_id] = std::move(Connection);
}
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
std::lock_guard Lock(WSServerMutex_);
auto Connection = Sessions_.find(session_id);
if (Connection != end(Sessions_))
return Connection->second;
return nullptr;
}
inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
std::lock_guard Lock(WSServerMutex_);
auto hashIndex = Utils::CalculateMacAddressHash(serialNumber);
std::lock_guard G(SerialNumbersMutex_[hashIndex]);
auto Connection = SerialNumbers_.find(serialNumber);
if (Connection==end(SerialNumbers_) || Connection->second.second==nullptr)
auto Connection = SerialNumbers_[hashIndex].find(serialNumber);
if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second.second==nullptr)
return false;
return Connection->second.second->RttyMustBeSecure_;
}
@@ -201,9 +192,9 @@ namespace OpenWifi {
RX = RX_;
}
// TOD: move to hash based map.
inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
std::lock_guard G(WSServerMutex_);
std::lock_guard Lock(SessionMutex_);
for(const auto &connection:Sessions_) {
if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit &&
connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
@@ -220,9 +211,12 @@ namespace OpenWifi {
std::double_t &Load,
std::double_t &Temperature
) {
std::lock_guard G(WSServerMutex_);
auto session_hint = SerialNumbers_.find(Utils::SerialNumberToInt(serialNumber));
if(session_hint==end(SerialNumbers_)) {
auto serialNumberInt = Utils::SerialNumberToInt(serialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(serialNumberInt);
std::lock_guard G(SerialNumbersMutex_[hashIndex]);
auto session_hint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber));
if(session_hint==end(SerialNumbers_[hashIndex])) {
return false;
}
hasGPS = session_hint->second.second->hasGPS;
@@ -234,7 +228,8 @@ namespace OpenWifi {
}
private:
mutable std::recursive_mutex WSServerMutex_;
mutable std::mutex SessionMutex_;
mutable std::mutex StatsMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::Net::SocketReactor Reactor_;
@@ -247,7 +242,13 @@ namespace OpenWifi {
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
std::atomic_bool Running_ = false;
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
std::map<uint64_t, std::pair<uint64_t, std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
using SerialNumberMap = std::map<uint64_t /* serial number */, std::pair<uint64_t /* session id*/,
std::shared_ptr<AP_WS_Connection>>>;
std::array<SerialNumberMap,256> SerialNumbers_;
mutable std::array<std::mutex,256> SerialNumbersMutex_;
std::atomic_bool AllowSerialNumberMismatch_ = true;
std::atomic_uint64_t MismatchDepth_ = 2;
@@ -255,7 +256,7 @@ namespace OpenWifi {
std::uint64_t AverageDeviceConnectionTime_ = 0;
std::uint64_t NumberOfConnectingDevices_ = 0;
std::uint64_t SessionTimeOut_ = 10*60;
mutable std::mutex StatsMutex_;
std::atomic_uint64_t TX_=0,RX_=0;
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;

View File

@@ -467,4 +467,16 @@ namespace OpenWifi {
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
return nullptr;
}
bool CommandManager::FireAndForget(const std::string &SerialNumber, const std::string &Method, const Poco::JSON::Object &Params) {
Poco::JSON::Object CompleteRPC;
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
CompleteRPC.set(uCentralProtocol::ID, 0);
CompleteRPC.set(uCentralProtocol::METHOD, Method);
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
std::stringstream ToSend;
CompleteRPC.stringify(ToSend);
poco_debug(Logger(), fmt::format("{}: Fire and forget command {}.", SerialNumber, Method));
return AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())>0;
}
} // namespace OpenWifi

View File

@@ -12,7 +12,7 @@
#include <functional>
#include <future>
#include <map>
#include <shared_mutex>
#include <mutex>
#include <utility>
#include "Poco/JSON/Object.h"
@@ -162,8 +162,10 @@ namespace OpenWifi {
inline auto CommandTimeout() const { return commandTimeOut_; }
inline auto CommandRetry() const { return commandRetry_; }
bool FireAndForget(const std::string &SerialNumber, const std::string &Method,
const Poco::JSON::Object &Params);
private:
mutable std::recursive_mutex LocalMutex_;
mutable std::mutex LocalMutex_;
std::atomic_bool Running_ = false;
Poco::Thread ManagerThread;
std::atomic_uint64_t Id_ = 3; // do not start @1. We ignore ID=1 & 0 is illegal..

View File

@@ -35,6 +35,7 @@
#include "VenueBroadcaster.h"
#include "AP_WS_ConfigAutoUpgrader.h"
#include "rttys/RTTYS_server.h"
#include "firmware_revision_cache.h"
namespace OpenWifi {
class Daemon *Daemon::instance() {
@@ -42,21 +43,34 @@ namespace OpenWifi {
vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
SubSystemVec{GenericScheduler(), StorageService(), SerialNumberCache(), ConfigurationValidator(),
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
SignatureManager(), AP_WS_Server(),
RegulatoryInfo(),
RADIUSSessionTracker(),
AP_WS_ConfigAutoUpgrader()
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
SignatureManager(), AP_WS_Server(),
RegulatoryInfo(),
RADIUSSessionTracker(),
AP_WS_ConfigAutoUpgrader(),
FirmwareRevisionCache()
});
return &instance;
}
static std::string ALBHealthCallback() {
uint64_t Connections, AverageConnectionTime, NumberOfConnectingDevices;
AP_WS_Server()->AverageDeviceStatistics(Connections, AverageConnectionTime,
NumberOfConnectingDevices);
std::ostringstream os;
os << "Connections: " << Connections << std::endl <<
"ConnectingDevices: " << NumberOfConnectingDevices << std::endl <<
"ConnectionTime: " << AverageConnectionTime << std::endl;
return os.str();
}
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
DeviceTypes_ = DefaultDeviceTypeList;
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
MicroServiceALBCallback(ALBHealthCallback);
}
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const {

View File

@@ -12,10 +12,7 @@ namespace OpenWifi {
Event.set("type", type_);
Event.set("timestamp", timestamp_);
Event.set("payload", payload_);
std::ostringstream OS;
Event.stringify(OS);
auto payload = std::make_shared<std::string>(OS.str());
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), payload);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), Event);
}
}

View File

@@ -50,17 +50,17 @@ namespace OpenWifi {
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
public:
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
std::uint64_t timestamp, const std::string config)
std::uint64_t timestamp, const Poco::JSON::Object::Ptr config)
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
}
~DeviceConfigurationChangeKafkaEvent() {
payload_->set("configuration", config_);
payload_->set("configuration", *config_);
Send();
}
private:
std::string config_;
Poco::JSON::Object::Ptr config_;
};
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {

View File

@@ -28,7 +28,7 @@ namespace OpenWifi {
bool Recovered = false;
Poco::File OuiFile(CurrentOUIFileName_);
if (OuiFile.exists()) {
std::unique_lock Lock(LocalMutex_);
std::lock_guard Lock(LocalMutex_);
Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
if (Recovered) {
poco_notice(Logger(),
@@ -150,7 +150,7 @@ namespace OpenWifi {
OUIMap TmpOUIs;
if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
std::unique_lock G(LocalMutex_);
std::lock_guard G(LocalMutex_);
OUIs_ = std::move(TmpOUIs);
LastUpdate_ = Utils::Now();
Poco::File F1(CurrentOUIFileName_);
@@ -163,7 +163,7 @@ namespace OpenWifi {
} else if (OUIs_.empty()) {
if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
LastUpdate_ = Utils::Now();
std::unique_lock G(LocalMutex_);
std::lock_guard G(LocalMutex_);
OUIs_ = std::move(TmpOUIs);
}
}
@@ -173,7 +173,7 @@ namespace OpenWifi {
}
std::string OUIServer::GetManufacturer(const std::string &MAC) {
std::shared_lock Lock(LocalMutex_);
std::lock_guard Lock(LocalMutex_);
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
if (Manufacturer != OUIs_.end())

View File

@@ -4,7 +4,7 @@
#pragma once
#include <shared_mutex>
#include <mutex>
#include "framework/SubSystemServer.h"
@@ -32,7 +32,7 @@ namespace OpenWifi {
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
private:
std::shared_mutex LocalMutex_;
std::mutex LocalMutex_;
uint64_t LastUpdate_ = 0;
bool Initialized_ = false;
OUIMap OUIs_;

View File

@@ -98,7 +98,7 @@ namespace OpenWifi {
void RADIUSSessionTracker::ProcessAuthenticationSession([[maybe_unused]] OpenWifi::SessionNotification &Notification) {
std::lock_guard Guard(Mutex_);
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface, nasId;
std::string CallingStationId, CalledStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface, nasId;
for (const auto &attribute : Notification.Packet_.Attrs_) {
switch (attribute.type) {
case RADIUS::Attributes::AUTH_USERNAME: {
@@ -111,6 +111,11 @@ namespace OpenWifi {
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CALLED_STATION_ID: {
CalledStationId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_SESSION_ID: {
AccountingSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
@@ -153,7 +158,7 @@ namespace OpenWifi {
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
}
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
auto Index = AccountingSessionId +AccountingMultiSessionId;
auto session_hint = ap_hint->second.find(Index);
if(session_hint==end(ap_hint->second)) {
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
@@ -161,6 +166,7 @@ namespace OpenWifi {
NewSession->started = NewSession->lastTransaction = Utils::Now();
NewSession->userName = UserName;
NewSession->callingStationId = CallingStationId;
NewSession->calledStationId = CalledStationId;
NewSession->accountingSessionId = AccountingSessionId;
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
NewSession->chargeableUserIdentity = ChargeableUserIdentity;
@@ -172,6 +178,14 @@ namespace OpenWifi {
session_hint->second->lastTransaction = Utils::Now();
}
/*
if(ap_hint!=AccountingSessions_.end()) {
std::cout << "Auth table:" << std::endl;
for(const auto &session:ap_hint->second) {
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
}
}
*/
}
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
@@ -188,7 +202,7 @@ namespace OpenWifi {
RADIUSSessionTracker::ProcessAccountingSession(OpenWifi::SessionNotification &Notification) {
std::lock_guard Guard(Mutex_);
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface;
std::string CallingStationId, CalledStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface;
std::uint8_t AccountingPacketType = 0;
std::uint32_t InputOctets=0, OutputOctets=0, InputPackets=0, OutputPackets=0, InputGigaWords=0, OutputGigaWords=0,
SessionTime = 0;
@@ -204,6 +218,11 @@ namespace OpenWifi {
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CALLED_STATION_ID: {
CalledStationId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_SESSION_ID: {
AccountingSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
@@ -258,7 +277,6 @@ namespace OpenWifi {
}
}
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
auto ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
if(ap_hint==end(AccountingSessions_)) {
SessionMap M;
@@ -266,6 +284,7 @@ namespace OpenWifi {
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
}
auto Index = AccountingSessionId + AccountingMultiSessionId;
auto session_hint = ap_hint->second.find(Index);
if(session_hint==end(ap_hint->second)) {
// find the calling_station_id
@@ -275,12 +294,15 @@ namespace OpenWifi {
return;
}
// std::cout << "ACT -> " << Notification.SerialNumber_ << ": AccountingSessionId: " << AccountingSessionId << " AccountingMultiSessionId: " << AccountingMultiSessionId << std::endl;
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
NewSession->serialNumber = Notification.SerialNumber_;
NewSession->destination = Notification.Destination_;
NewSession->started = NewSession->lastTransaction = Utils::Now();
NewSession->userName = UserName;
NewSession->callingStationId = CallingStationId;
NewSession->calledStationId = CalledStationId;
NewSession->accountingSessionId = AccountingSessionId;
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
NewSession->accountingPacket = Notification.Packet_;
@@ -319,6 +341,14 @@ namespace OpenWifi {
session_hint->second->sessionTime = SessionTime;
}
}
/* if(ap_hint!=AccountingSessions_.end()) {
std::cout << "Acct table:" << std::endl;
for(const auto &session:ap_hint->second) {
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
}
}
*/
}
[[maybe_unused]] static void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size, int i) {
@@ -340,18 +370,19 @@ namespace OpenWifi {
P.Identifier(std::rand() & 0x00ff);
P.AppendAttribute(RADIUS::Attributes::AUTH_USERNAME, session->userName);
P.AppendAttribute(RADIUS::Attributes::NAS_IP, (std::uint32_t)(0x7f000001));
P.AppendAttribute(RADIUS::Attributes::CALLING_STATION_ID, session->callingStationId);
if(!session->calledStationId.empty())
P.AppendAttribute(RADIUS::Attributes::CALLED_STATION_ID, session->calledStationId);
if(!session->callingStationId.empty())
P.AppendAttribute(RADIUS::Attributes::CALLING_STATION_ID, session->callingStationId);
if(!session->nasId.empty())
P.AppendAttribute(RADIUS::Attributes::NAS_IDENTIFIER, session->nasId);
if(!session->accountingSessionId.empty())
P.AppendAttribute(RADIUS::Attributes::ACCT_SESSION_ID, session->accountingSessionId);
if(!session->accountingMultiSessionId.empty())
P.AppendAttribute(RADIUS::Attributes::ACCT_MULTI_SESSION_ID, session->accountingMultiSessionId);
if(!session->chargeableUserIdentity.empty())
P.AppendAttribute(RADIUS::Attributes::CHARGEABLE_USER_IDENTITY, session->chargeableUserIdentity);
if(!session->nasId.empty())
P.AppendAttribute(RADIUS::Attributes::NAS_IDENTIFIER, session->nasId);
auto ProxyState = session->serialNumber + ":" + "0.0.0.0" + ":" + "3799" + ":" + session->interface;
std::cout << "Proxy state: " << ProxyState << " Secret: " << session->secret << std::endl;
// P.AppendAttribute(RADIUS::PROXY_STATE, ProxyState);
// std::cout << "Proxy state: " << ProxyState << " Secret: " << session->secret << std::endl;
P.AppendAttribute(RADIUS::Attributes::PROXY_STATE, ProxyState);
P.RecomputeAuthenticator(session->secret);
P.Log(std::cout);
AP_WS_Server()->SendRadiusCoAData(session->serialNumber, P.Buffer(), P.Size_);
@@ -368,9 +399,23 @@ namespace OpenWifi {
return false;
}
for(const auto &[_,session]:ap_hint->second) {
if(session->accountingSessionId==sessionId) {
SendCoADM(session);
auto session_hint = ap_hint->second.find(sessionId);
if(session_hint!=ap_hint->second.end()) {
SendCoADM(session_hint->second);
}
return true;
}
bool RADIUSSessionTracker::DisconnectUser(const std::string &UserName) {
poco_information(Logger(),fmt::format("Disconnect user {}.", UserName));
std::lock_guard Guard(Mutex_);
for(const auto &AP:AccountingSessions_) {
for(const auto &Session:AP.second) {
if(Session.second->userName==UserName) {
SendCoADM(Session.second);
}
}
}

View File

@@ -165,6 +165,7 @@ namespace OpenWifi {
bool SendCoADM(const std::string &serialNumber, const std::string &sessionId);
bool SendCoADM(const RADIUSSessionPtr &session);
bool DisconnectUser(const std::string &UserName);
inline std::uint32_t HasSessions(const std::string & serialNumber) {
std::lock_guard G(Mutex_);

740
src/RADIUS_Destination.h Normal file
View File

@@ -0,0 +1,740 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <fstream>
#include <iostream>
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/TemporaryFile.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "AP_WS_Server.h"
#include "RADIUS_helpers.h"
#include <RESTObjects/RESTAPI_GWobjects.h>
namespace OpenWifi {
class RADIUS_Destination : public Poco::Runnable {
public:
RADIUS_Destination(Poco::Net::SocketReactor &R, const GWObjects::RadiusProxyPool &P)
: Reactor_(R),
Logger_(Poco::Logger::get(
fmt::format("RADSEC: {}", P.name))),
Pool_(P)
{
Type_ = GWObjects::RadiusEndpointType(P.radsecPoolType);
Start();
}
~RADIUS_Destination() override { Stop(); }
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
inline int Start() {
ReconnectThread_.start(*this);
return 0;
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectThread_.wakeUp();
ReconnectThread_.join();
}
inline void run() final {
Poco::Thread::trySleep(5000);
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
while (TryAgain_) {
if (!Connected_) {
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
LastTry = Utils::Now();
if (!Connect()) {
CurrentDelay *= 2;
if(CurrentDelay>maxDelay) CurrentDelay=10;
} else {
CurrentDelay = 10;
}
}
} else if ((Utils::Now() - LastKeepAlive) > Pool_.radsecKeepAlive) {
RADIUS::RadiusOutputPacket P(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
P.MakeStatusMessage(Pool_.authConfig.servers[ServerIndex_].name);
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Pool_.authConfig.servers[ServerIndex_].name));
Socket_->sendBytes(P.Data(), P.Len());
LastKeepAlive = Utils::Now();
}
Poco::Thread::trySleep(2000);
}
}
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
int length) {
try {
if (Connected_) {
RADIUS::RadiusPacket P(buffer, length);
int sent_bytes;
if (P.VerifyMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret)) {
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
sent_bytes = Socket_->sendBytes(buffer, length);
} else {
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
P.ComputeMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
}
return (sent_bytes == length);
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Exception occurred: while sending data.");
}
return false;
}
inline void
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
unsigned char Buffer[4096];
try {
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
std::string ReplySource;
if (NumberOfReceivedBytes >= 20) {
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
if (P.IsAuthentication()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(),
NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else if(P.IsStatusMessageReply(ReplySource)) {
poco_debug(Logger_,
fmt::format("{}: Keepalive message received.", ReplySource));
} else {
poco_debug(Logger_, "AUTH packet dropped.");
}
} else if (P.IsAccounting()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "ACCT packet dropped.");
}
} else if (P.IsAuthority()) {
auto SerialNumber = P.ExtractSerialNumberTIP();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "CoA/DM packet dropped.");
}
} else {
poco_warning(Logger_,
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
}
} else {
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
Disconnect();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Disconnect();
} catch (...) {
Disconnect();
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
}
}
inline void
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_warning(Logger_, "Socker error. Terminating connection.");
Disconnect();
}
inline void
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
Disconnect();
}
inline void OnAccountingSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "Accounting: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger_, "Accounting: missing serial number. Dropping request.");
return;
}
poco_debug(
Logger_,
fmt::format(
"Accounting Packet Response received for {}", SerialNumber ));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
}
inline void OnAuthenticationSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "Authentication: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
if(Logger_.trace()) {
P.Log(std::cout);
}
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger_, "Authentication: missing serial number. Dropping request.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger_,
fmt::format(
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
}
inline void OnCoASocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "CoA/DM: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if (SerialNumber.empty()) {
poco_warning(Logger_, "CoA/DM: missing serial number. Dropping request.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger_,
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
}
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
}
static inline void Cat(const std::string &F1, const std::string & F2, const std::string &F) {
std::ofstream of(F.c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary);
std::ifstream if1(F1.c_str(),std::ios_base::binary|std::ios_base::in);
Poco::StreamCopier::copyStream(if1,of);
of << std::endl;
std::ifstream if2(F2.c_str(),std::ios_base::binary|std::ios_base::in);
Poco::StreamCopier::copyStream(if2,of);
of << std::endl;
of.close();
}
inline bool Connect_GlobalReach() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
DecodeFile(Intermediate0.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[0]);
DecodeFile(Intermediate1.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[1]);
const static std::string OpenRoamingRootCert{
"-----BEGIN CERTIFICATE-----\n"
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
"-----END CERTIFICATE-----\n"};
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),
std::ios_base::trunc | std::ios_base::out |
std::ios_base::binary};
ofs << OpenRoamingRootCert;
ofs.close();
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""));
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("", KeyFile_.path(), ""));
Poco::Crypto::X509Certificate Cert(CertFile_.path());
if (!IsExpired(Cert)) {
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
} else {
poco_error(
Logger_,
fmt::format(
"Certificate for {} has expired. We cannot connect to this server.",
Pool_.acctConfig.servers[ServerIndex_].name));
return false;
}
SecureContext->addCertificateAuthority(
Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
SecureContext->addChainCertificate(
Poco::Crypto::X509Certificate(Intermediate0.path()));
SecureContext->addChainCertificate(
Poco::Crypto::X509Certificate(Intermediate1.path()));
SecureContext->enableExtendedCertificateVerification(false);
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
ServerIndex_ = 0 ;
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
try {
poco_information(Logger_, fmt::format("Attempting to connect to {}", CommonName()));
Socket_->connect(Destination, Poco::Timespan(20, 0));
Socket_->completeHandshake();
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_warning(Logger_, "NetException: Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_warning(Logger_, "Exception: Could not connect.");
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Could not connect.");
}
ServerIndex_++;
}
}
ServerIndex_=0;
return false;
}
inline bool Connect_Orion() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
Poco::Crypto::X509Certificate Cert(CertFile_.path());
if(IsExpired(Cert)) {
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Pool_.acctConfig.servers[ServerIndex_].name));
return false;
}
for (auto &cert : Pool_.acctConfig.servers[ServerIndex_].radsecCacerts) {
CaCertFiles_.emplace_back(
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
}
Poco::Net::Context::Ptr SecureContext =
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
for (const auto &ca : CaCertFiles_) {
Poco::Crypto::X509Certificate cert(ca->path());
SecureContext->addCertificateAuthority(cert);
}
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
ServerIndex_ = 0 ;
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
try {
poco_information(Logger_, "Attempting to connect");
Socket_->connect(Destination, Poco::Timespan(100, 0));
Socket_->completeHandshake();
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (...) {
poco_information(Logger_, "Could not connect.");
}
ServerIndex_++;
}
}
ServerIndex_=0;
return false;
}
inline bool Connect_Generic() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::Net::SocketAddress AuthSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
Poco::Net::SocketAddress AcctSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
Poco::Net::SocketAddress CoASockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
/*
AuthenticationSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
Poco::Net::SocketAddress AuthSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
Poco::Net::SocketAddress AcctSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
Poco::Net::SocketAddress CoASockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
*/
Reactor_.addEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
Reactor_.addEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
Reactor_.addEventHandler(
*CoASocketV4_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
/*
Reactor_.addEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
Reactor_.addEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
Reactor_.addEventHandler(
*CoASocketV6_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
*/
}
return true;
}
inline bool Connect_Radsec() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
}
return true;
}
inline bool Connect() {
switch(Type_) {
case GWObjects::RadiusEndpointType::orion: return Connect_Orion();
case GWObjects::RadiusEndpointType::globalreach: return Connect_GlobalReach();
case GWObjects::RadiusEndpointType::radsec: return Connect_Radsec();
default:
return Connect_Generic();
}
}
inline void Disconnect() {
if (Connected_) {
std::lock_guard G(LocalMutex_);
if(Type_==GWObjects::RadiusEndpointType::generic) {
if(AuthenticationSocketV4_) {
Reactor_.removeEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
AuthenticationSocketV4_->close();
AuthenticationSocketV4_.reset();
}
if(AccountingSocketV4_) {
Reactor_.removeEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
AccountingSocketV4_->close();
AccountingSocketV4_.reset();
}
if(CoASocketV4_) {
Reactor_.removeEventHandler(
*CoASocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
CoASocketV4_->close();
CoASocketV4_.reset();
}
/* if(AuthenticationSocketV6_) {
Reactor_.removeEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
AuthenticationSocketV6_->close();
AuthenticationSocketV6_.reset();
}
if(AccountingSocketV6_) {
Reactor_.removeEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
AccountingSocketV6_->close();
AccountingSocketV6_.reset();
}
if(CoASocketV6_) {
Reactor_.removeEventHandler(
*CoASocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
CoASocketV6_->close();
CoASocketV6_.reset();
}
*/
} else {
if(Socket_!=nullptr) {
std::lock_guard G(LocalMutex_);
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.removeEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Socket_->close();
}
}
}
Connected_ = false;
poco_information(Logger_, "Disconnecting.");
}
static void DecodeFile(const std::string &filename, const std::string &s) {
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
std::ios_base::binary);
std::stringstream is(s);
Poco::Base64Decoder ds(is);
Poco::StreamCopier::copyStream(ds, sec_file);
sec_file.close();
}
[[nodiscard]] inline std::string CommonName() {
if (Peer_Cert_)
return Peer_Cert_->commonName();
return "";
}
[[nodiscard]] inline std::string IssuerName() {
if (Peer_Cert_)
return Peer_Cert_->issuerName();
return "";
}
[[nodiscard]] inline std::string SubjectName() {
if (Peer_Cert_)
return Peer_Cert_->subjectName();
return "";
}
const auto &Pool() const { return Pool_; }
auto ServerType() const { return Type_; }
inline bool SendRadiusDataAuthData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Auth {} bytes.", serialNumber, size));
AuthenticationSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.authConfig.servers[0].ip, Pool_.authConfig.servers[0].port));
return true;
}
inline bool SendRadiusDataAcctData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Acct {} bytes.", serialNumber, size));
AccountingSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.acctConfig.servers[0].ip, Pool_.acctConfig.servers[0].port));
return true;
}
inline bool SendRadiusDataCoAData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS CoA {} bytes.", serialNumber, size));
CoASocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.coaConfig.servers[0].ip, Pool_.coaConfig.servers[0].port));
return true;
}
private:
std::recursive_mutex LocalMutex_;
Poco::Net::SocketReactor &Reactor_;
Poco::Logger &Logger_;
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
/* std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
*/
Poco::Thread ReconnectThread_;
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
volatile bool Connected_ = false;
volatile bool TryAgain_ = true;
enum GWObjects::RadiusEndpointType Type_{GWObjects::RadiusEndpointType::unknown};
GWObjects::RadiusProxyPool Pool_;
uint64_t ServerIndex_=0;
};
} // namespace OpenWifi

View File

@@ -14,6 +14,8 @@
#include "Poco/Net/SocketAddress.h"
#include "Poco/StringTokenizer.h"
#include <framework/utils.h>
namespace OpenWifi::RADIUS {
// Packet types
@@ -66,6 +68,7 @@ namespace OpenWifi::RADIUS {
constexpr std::uint8_t ACCT_INPUT_GIGAWORDS = 52;
constexpr std::uint8_t ACCT_OUTPUT_GIGAWORDS = 53;
constexpr std::uint8_t EVENT_TIMESTAMP = 55;
constexpr std::uint8_t TUNNEL_PRIVATE_GROUP_ID = 81;
constexpr std::uint8_t MESSAGE_AUTHENTICATOR = 80;
constexpr std::uint8_t CHARGEABLE_USER_IDENTITY = 89;
};
@@ -406,6 +409,15 @@ namespace OpenWifi::RADIUS {
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
[[nodiscard]] inline std::string PacketTypeToString() const {
for(auto const &Name:radius_command_values) {
if(Name.cmd == P_.code)
return Name.name;
}
return "Unknown";
}
inline bool IsAuthentication() {
return (P_.code == RADIUS::Access_Request || P_.code == RADIUS::Access_Accept ||
P_.code == RADIUS::Access_Challenge || P_.code == RADIUS::Access_Reject ||
@@ -426,6 +438,25 @@ namespace OpenWifi::RADIUS {
P_.code == RADIUS::CoA_ACK || P_.code == RADIUS::CoA_NAK);
}
inline bool IsStatusMessageReply(std::string &ReplySource) {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::PROXY_STATE) {
std::string Attr33;
// format is statis:server name
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len);
auto Parts = Poco::StringTokenizer(Attr33, ":");
if(Parts.count() == 2 && Parts[0] == "status") {
ReplySource = Parts[1];
return true;
}
return false;
}
}
DBGLINE
return false;
}
void Log(std::ostream &os) {
uint16_t p = 0;
@@ -622,7 +653,7 @@ namespace OpenWifi::RADIUS {
std::string Attr33;
// format is serial:IP:port:interface
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
attribute.len);
auto Parts = Poco::StringTokenizer(Attr33, "|");
if (Parts.count() == 4) {
return Parts[0];
@@ -645,7 +676,7 @@ namespace OpenWifi::RADIUS {
// format is
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
attribute.len);
auto Parts = Poco::StringTokenizer(Attr33, "|");
if (Parts.count() == 4) {
Poco::Net::SocketAddress D(Parts[1], Parts[2]);
@@ -662,12 +693,35 @@ namespace OpenWifi::RADIUS {
return Result;
}
std::uint32_t ExtractProxyStateDestinationIPint() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::PROXY_STATE && attribute.len > 2) {
std::string Attr33;
// format is
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len);
auto Parts = Poco::StringTokenizer(Attr33, "|");
if (Parts.count() == 4) {
return Utils::IPtoInt(Parts[1]);
}
Parts = Poco::StringTokenizer(Attr33, ":");
if (Parts.count() == 4) {
return Utils::IPtoInt(Parts[1]);
}
return 0;
}
}
return 0;
}
std::string ExtractCallingStationID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::CALLING_STATION_ID && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::CALLING_STATION_ID && attribute.len > 0) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
attribute.len);
return Result;
}
}
@@ -677,9 +731,21 @@ namespace OpenWifi::RADIUS {
std::string ExtractAccountingSessionID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::ACCT_SESSION_ID && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::ACCT_SESSION_ID && attribute.len > 0) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
attribute.len );
return Result;
}
}
return Result;
}
std::string ExtractAccountingMultiSessionID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::ACCT_MULTI_SESSION_ID && attribute.len > 0) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len );
return Result;
}
}
@@ -689,9 +755,9 @@ namespace OpenWifi::RADIUS {
std::string ExtractCalledStationID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::CALLED_STATION_ID && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::CALLED_STATION_ID && attribute.len > 0) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
attribute.len);
return Result;
}
}
@@ -949,27 +1015,30 @@ namespace OpenWifi::RADIUS {
public:
explicit RadiusOutputPacket(const std::string &Secret) : Secret_(Secret) {}
inline void MakeStatusMessage() {
inline void MakeStatusMessage(const std::string &Source) {
P_.code = RADIUS::Status_Server;
P_.identifier = std::rand() & 0x00ff;
MakeRadiusAuthenticator(P_.authenticator);
unsigned char MessageAuthenticator[16]{0};
std::string FullSource = "status:" + Source;
AddAttribute(RADIUS::Attributes::PROXY_STATE, FullSource.size(), (const unsigned char *)FullSource.c_str());
AddAttribute(RADIUS::Attributes::MESSAGE_AUTHENTICATOR, sizeof(MessageAuthenticator),
MessageAuthenticator);
int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
// int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16 ;
int PktLen = 1 + 1 + 2 + 16 + AttributesLen_;
P_.rawlen = htons(PktLen);
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
H.update((const unsigned char *)&P_, PktLen);
auto digest = H.digest();
int p = 0;
int p = 0, offset = (int)FullSource.size() + 2 ;
for (const auto &i : digest)
P_.attributes[1 + 1 + p++] = i;
P_.attributes[offset + 1 + 1 + p++] = i;
}
inline void AddAttribute(unsigned char attr, uint8_t len, const unsigned char *data) {
P_.attributes[AttributesLen_++] = attr;
P_.attributes[AttributesLen_++] = len;
P_.attributes[AttributesLen_++] = len+2;
memcpy(&P_.attributes[AttributesLen_], data, len);
AttributesLen_ += len;
}

View File

@@ -13,12 +13,12 @@
namespace OpenWifi {
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
/*
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
*/
int RADIUS_proxy_server::Start() {
@@ -27,7 +27,7 @@ namespace OpenWifi {
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false);
if (!Enabled_ && !Config.exists()) {
StopRADSECServers();
StopRADIUSDestinations();
return 0;
}
@@ -35,278 +35,81 @@ namespace OpenWifi {
Enabled_ = true;
Poco::Net::SocketAddress AuthSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
Poco::Net::SocketAddress AuthSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
Poco::Net::SocketAddress AcctSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
Poco::Net::SocketAddress AcctSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
Poco::Net::SocketAddress CoASockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
Poco::Net::SocketAddress CoASockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
RadiusReactor_.reset();
RadiusReactor_ = std::make_unique<Poco::Net::SocketReactor>();
RadiusReactor_->addEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->addEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->addEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->addEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->addEventHandler(
*CoASocketV4_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
RadiusReactor_->addEventHandler(
*CoASocketV6_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
ParseConfig();
StartRADSECServers();
RadiusReactorThread_.start(*RadiusReactor_);
StartRADIUSDestinations();
RadiusReactorThread_.start(RadiusReactor_);
Utils::SetThreadName(RadiusReactorThread_, "rad:reactor");
Running_ = true;
return 0;
}
void RADIUS_proxy_server::Stop() {
if (Enabled_ && Running_) {
poco_information(Logger(), "Stopping...");
RadiusReactor_->removeEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->removeEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->removeEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->removeEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->removeEventHandler(
*CoASocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
RadiusReactor_->removeEventHandler(
*CoASocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
AuthenticationSocketV4_->close();
AuthenticationSocketV6_->close();
AccountingSocketV4_->close();
AccountingSocketV6_->close();
CoASocketV4_->close();
CoASocketV6_->close();
AuthenticationSocketV4_.reset();
AuthenticationSocketV6_.reset();
AccountingSocketV4_.reset();
AccountingSocketV6_.reset();
CoASocketV4_.reset();
CoASocketV6_.reset();
StopRADSECServers();
RadiusReactor_->stop();
StopRADIUSDestinations();
RadiusReactor_.stop();
RadiusReactorThread_.join();
Running_ = false;
poco_information(Logger(), "Stopped...");
}
}
void RADIUS_proxy_server::StartRADSECServers() {
/* inline static bool isRadsec(const GWObjects::RadiusProxyPool &Cfg) {
return Cfg.radsecPoolType=="orion" || Cfg.radsecPoolType=="globalreach" || Cfg.radsecPoolType=="radsec";
}
*/
void RADIUS_proxy_server::StartRADIUSDestinations() {
std::lock_guard G(Mutex_);
for (const auto &pool : PoolList_.pools) {
for (const auto &entry : pool.authConfig.servers) {
if (entry.radsec) {
RADSECservers_[Poco::Net::SocketAddress(entry.ip, 0)] =
std::make_unique<RADSEC_server>(*RadiusReactor_, entry);
}
if(pool.enabled) {
RADIUS_Destinations_[Utils::IPtoInt(pool.poolProxyIp)] =
std::make_unique<RADIUS_Destination>(RadiusReactor_, pool);
} else {
poco_information(Logger(),fmt::format("Pool {} is not enabled.", pool.name));
}
}
}
void RADIUS_proxy_server::StopRADSECServers() {
void RADIUS_proxy_server::StopRADIUSDestinations() {
std::lock_guard G(Mutex_);
RADSECservers_.clear();
RADIUS_Destinations_.clear();
}
void RADIUS_proxy_server::OnAccountingSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "Accounting: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
// P.Log(std::cout);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Accounting: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger(),
fmt::format(
"Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::OnAuthenticationSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "Authentication: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
// P.Log(std::cout);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Authentication: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger(),
fmt::format(
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::OnCoASocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "CoA/DM: bad packet received.");
return;
}
// P.Log(std::cout);
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if (SerialNumber.empty()) {
poco_warning(Logger(), "CoA/DM: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger(),
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string & secret) {
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination,const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string &Secret) {
try{
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
// are we sending this to a pool?
auto DstParts = Utils::Split(Destination, ':');
std::uint32_t DtsIp = Utils::IPtoInt(DstParts[0]);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC, secret);
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
auto DestinationServer = RADIUS_Destinations_.find(DtsIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
if(Logger().trace()) {
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
auto SessionID = P.ExtractAccountingSessionID();
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
Logger().trace(
fmt::format("{}: Sending Accounting {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
serialNumber, P.Size(),
DestinationServer->second->Pool().authConfig.servers[0].ip,
CalledStationID, CallingStationID, SessionID, MultiSessionID));
}
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
Secret = DestinationServer->second->Pool().acctConfig.servers[0].secret;
if(RecomputeAuthenticator) {
P.RecomputeAuthenticator("radsec");
P.RecomputeAuthenticator(Secret);
}
DestinationServer->second->SendData(serialNumber, P.Buffer(), P.Size());
DestinationServer->second->SendData(serialNumber, (const unsigned char *)P.Buffer(),
P.Size());
} else {
DestinationServer->second->SendRadiusDataAcctData(
serialNumber, (const unsigned char *)P.Buffer(), P.Size());
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
AccountingSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AccountingSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
if(RecomputeAuthenticator) {
P.RecomputeAuthenticator(secret);
}
auto AllSent =
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
: *AccountingSocketV6_
, P.Buffer(), P.Size(), FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Accounting packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, "
"CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -326,22 +129,18 @@ namespace OpenWifi {
ofs.close();
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
const char *buffer, std::size_t size, std::string & secret) {
void RADIUS_proxy_server::SendAccountingData( const std::string &serialNumber,
const char *buffer, std::size_t size) {
if (!Continue())
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
// P.Log(std::cout);
auto Destination = P.ExtractProxyStateDestination();
// store_packet(serialNumber, buffer, size);
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, secret);
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, secret);
std::string Secret;
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, Secret);
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, Secret);
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
@@ -356,58 +155,38 @@ namespace OpenWifi {
}
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber,
const char *buffer, std::size_t size, std::string & secret) {
const char *buffer, std::size_t size) {
if (!Continue())
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
// P.Log(std::cout);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC, secret);
RADIUSSessionTracker()->AddAuthenticationSession(Destination, serialNumber, P, secret);
// std::cout << "Authentication secret: " << secret << std::endl;
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
if(Logger().trace()) {
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
auto SessionID = P.ExtractAccountingSessionID();
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
Logger().trace(
fmt::format("{}: Sending Authentication {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
serialNumber, P.Size(),
DestinationServer->second->Pool().authConfig.servers[0].ip,
CalledStationID, CallingStationID, SessionID, MultiSessionID));
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
AuthenticationSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AuthenticationSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
DestinationServer->second->SendData(serialNumber,
(const unsigned char *)buffer, size);
}
else {
DestinationServer->second->SendRadiusDataAuthData(
serialNumber, (const unsigned char *)buffer, size);
}
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4
? *AuthenticationSocketV4_
: *AuthenticationSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Authentication packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, "
"CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -418,64 +197,42 @@ namespace OpenWifi {
}
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer,
std::size_t size, std::string & secret) {
std::size_t size) {
if (!Continue())
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
if (Destination.empty()) {
Destination = "0.0.0.0:0";
}
P.Log(std::cout);
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC, secret);
std::cout << "CoA secret: " << secret << std::endl;
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
poco_trace(Logger(),fmt::format("{}: Sending CoA {} bytes to {}", serialNumber, P.Size(), DestinationServer->second->Pool().coaConfig.servers[0].ip));
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
} else {
DestinationServer->second->SendRadiusDataCoAData(
serialNumber, (const unsigned char *)buffer, size);
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent = SendData(
Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_ : *CoASocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(), fmt::format("{}: Could not send CoA packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
FinalDestination.toString()));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),
fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.", serialNumber));
fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.", serialNumber));
}
}
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
std::vector<Destination> &V4,
std::vector<Destination> &V6, bool setAsDefault) {
std::vector<Destination> &V6, bool setAsDefault,
const std::string &poolProxyIp) {
uint64_t TotalV4 = 0, TotalV6 = 0;
for (const auto &server : Config.servers) {
@@ -499,7 +256,8 @@ namespace OpenWifi {
.useAsDefault = setAsDefault,
.useRADSEC = server.radsec,
.realms = server.radsecRealms,
.secret = server.secret };
.secret = server.secret,
.poolProxyIp = poolProxyIp};
if (setAsDefault && D.useRADSEC)
DefaultIsRADSEC_ = true;
@@ -548,11 +306,11 @@ namespace OpenWifi {
for (const auto &pool : RPC.pools) {
RadiusPool NewPool;
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6,
pool.useByDefault);
pool.useByDefault, pool.poolProxyIp);
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6,
pool.useByDefault);
pool.useByDefault, pool.poolProxyIp);
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6,
pool.useByDefault);
pool.useByDefault, pool.poolProxyIp);
Pools_.push_back(NewPool);
}
} else {
@@ -571,6 +329,7 @@ namespace OpenWifi {
}
}
/*
static bool RealmMatch(const std::string &user_realm, const std::string &realm) {
if (realm.find_first_of('*') == std::string::npos)
return user_realm == realm;
@@ -582,6 +341,7 @@ namespace OpenWifi {
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret) {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
// find the realm...
@@ -596,7 +356,6 @@ namespace OpenWifi {
if (!server.realms.empty()) {
for (const auto &realm : server.realms) {
if (RealmMatch(UserRealm, realm)) {
// std::cout << "Realm match..." << std::endl;
UseRADSEC = true;
return server.Addr;
}
@@ -618,17 +377,17 @@ namespace OpenWifi {
: Pools_[DefaultPoolIndex_].AuthV6,
RequestedAddress, Secret);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress, Secret);
}
case radius_type::acct:
default: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
: Pools_[DefaultPoolIndex_].AcctV6,
RequestedAddress, Secret);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress, Secret);
}
}
}
@@ -637,7 +396,6 @@ namespace OpenWifi {
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret) {
std::lock_guard G(Mutex_);
if (Pools_.empty()) {
UseRADSEC = false;
@@ -646,6 +404,7 @@ namespace OpenWifi {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
bool useDefault;
useDefault = IsV4 ? RequestedAddress.host() ==
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4)
: RequestedAddress.host() ==
@@ -656,29 +415,36 @@ namespace OpenWifi {
}
auto isAddressInPool = [&](const std::vector<Destination> &D, bool &UseRADSEC) -> bool {
for (const auto &entry : D)
for (const auto &entry : D) {
if (!entry.poolProxyIp.empty() &&
entry.poolProxyIp == RequestedAddress.host().toString()) {
UseRADSEC = entry.useRADSEC;
return true;
}
if (entry.Addr.host() == RequestedAddress.host()) {
UseRADSEC = entry.useRADSEC;
return true;
}
}
return false;
};
for (auto &i : Pools_) {
for (auto &pool : Pools_) {
// try and match the pool's address to the destination
switch (rtype) {
case radius_type::coa: {
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? pool.CoaV4 : pool.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.CoaV4 : pool.CoaV6, RequestedAddress, Secret);
}
} break;
case radius_type::auth: {
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? pool.AuthV4 : pool.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AuthV4 : pool.AuthV6, RequestedAddress, Secret);
}
} break;
case radius_type::acct: {
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? pool.AcctV4 : pool.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AcctV4 : pool.AcctV6, RequestedAddress, Secret);
}
} break;
}
@@ -695,7 +461,8 @@ namespace OpenWifi {
if (Pool.size() == 1) {
Secret = Pool[0].secret;
return Pool[0].Addr;
auto A = Pool[0].Addr;
return A;
}
if (Pool[0].strategy == "weighted") {
@@ -741,7 +508,7 @@ namespace OpenWifi {
}
if (!found) {
return OriginalAddress;
// return OriginalAddress;
}
Pool[index].state += 1;
@@ -757,7 +524,7 @@ namespace OpenWifi {
}
return OriginalAddress;
}
*/
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
std::lock_guard G(Mutex_);

View File

@@ -11,7 +11,7 @@
#include "framework/SubSystemServer.h"
#include "RADSEC_server.h"
#include "RADIUS_Destination.h"
namespace OpenWifi {
@@ -28,25 +28,19 @@ namespace OpenWifi {
void Stop() final;
inline bool Enabled() const { return Enabled_; }
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void
OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void SendAccountingData(const std::string &serialNumber, const char *buffer,
std::size_t size, std::string & secret);
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
void SendAuthenticationData(const std::string &serialNumber, const char *buffer,
std::size_t size, std::string & secret);
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size, std::string & secret);
std::size_t size);
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string & secret);
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string &Secret);
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
void DeleteConfig();
void GetConfig(GWObjects::RadiusProxyPoolList &C);
void StartRADSECServers();
void StopRADSECServers();
void StartRADIUSDestinations();
void StopRADIUSDestinations();
struct Destination {
Poco::Net::SocketAddress Addr;
@@ -62,24 +56,19 @@ namespace OpenWifi {
bool useRADSEC = false;
std::vector<std::string> realms;
std::string secret;
std::string poolProxyIp;
};
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
private:
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
std::unique_ptr<Poco::Net::SocketReactor> RadiusReactor_;
Poco::Thread RadiusReactorThread_;
Poco::Net::SocketReactor RadiusReactor_;
Poco::Thread RadiusReactorThread_;
GWObjects::RadiusProxyPoolList PoolList_;
std::string ConfigFilename_;
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
std::map<std::uint32_t, std::unique_ptr<RADIUS_Destination>> RADIUS_Destinations_;
struct RadiusPool {
std::vector<Destination> AuthV4;
@@ -104,19 +93,21 @@ namespace OpenWifi {
void ParseConfig();
void ResetConfig();
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
// Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
// const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
void ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
std::vector<Destination> &V4, std::vector<Destination> &V6,
bool setAsDefault);
static Poco::Net::SocketAddress
std::vector<Destination> &V4,
std::vector<Destination> &V6, bool setAsDefault,
const std::string &poolProxyIp);
/* static Poco::Net::SocketAddress
ChooseAddress(std::vector<Destination> &Pool,
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret);
};
*/ };
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }

View File

@@ -1,304 +0,0 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <fstream>
#include <iostream>
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/TemporaryFile.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "AP_WS_Server.h"
#include "RADIUS_helpers.h"
namespace OpenWifi {
class RADSEC_server : public Poco::Runnable {
public:
RADSEC_server(Poco::Net::SocketReactor &R, GWObjects::RadiusProxyServerEntry E)
: Reactor_(R), Server_(std::move(E)),
Logger_(Poco::Logger::get(
fmt::format("RADSEC: {}@{}:{}", Server_.name, Server_.ip, Server_.port))) {
Start();
}
~RADSEC_server() { Stop(); }
inline int Start() {
ReconnectThread_.start(*this);
return 0;
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectThread_.wakeUp();
ReconnectThread_.join();
}
inline void run() final {
Poco::Thread::trySleep(3000);
std::uint64_t LastStatus = 0;
auto RadSecKeepAlive = MicroServiceConfigGetInt("radsec.keepalive", 120);
while (TryAgain_) {
if (!Connected_) {
std::lock_guard G(LocalMutex_);
LastStatus = Utils::Now();
Connect();
} else if ((Utils::Now() - LastStatus) > RadSecKeepAlive) {
RADIUS::RadiusOutputPacket P(Server_.radsecSecret);
P.MakeStatusMessage();
poco_information(Logger_, "Keep-Alive message.");
Socket_->sendBytes(P.Data(), P.Len());
LastStatus = Utils::Now();
}
Poco::Thread::trySleep(!Connected_ ? 3000 : 10000);
}
}
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
int length) {
try {
if (Connected_) {
RADIUS::RadiusPacket P(buffer, length);
int sent_bytes;
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
sent_bytes = Socket_->sendBytes(buffer, length);
} else {
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
P.ComputeMessageAuthenticator(Server_.radsecSecret);
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
}
return (sent_bytes == length);
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Exception occurred: while sending data.");
}
return false;
}
inline void
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
unsigned char Buffer[4096];
try {
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
if (NumberOfReceivedBytes >= 20) {
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
if (P.IsAuthentication()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "AUTH packet dropped.");
}
} else if (P.IsAccounting()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "ACCT packet dropped.");
}
} else if (P.IsAuthority()) {
auto SerialNumber = P.ExtractSerialNumberTIP();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "CoA/DM packet dropped.");
}
} else {
poco_warning(Logger_,
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
}
} else {
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
Disconnect();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Disconnect();
} catch (...) {
Disconnect();
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
}
}
inline void
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_warning(Logger_, "Socker error. Terminating connection.");
Disconnect();
}
inline void
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
Disconnect();
}
inline bool Connect() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
DecodeFile(CertFile_.path(), Server_.radsecCert);
DecodeFile(KeyFile_.path(), Server_.radsecKey);
for (auto &cert : Server_.radsecCacerts) {
CaCertFiles_.emplace_back(
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
}
Poco::Net::Context::Ptr SecureContext =
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
if (Server_.allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
for (const auto &ca : CaCertFiles_) {
Poco::Crypto::X509Certificate cert(ca->path());
SecureContext->addCertificateAuthority(cert);
}
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
try {
poco_information(Logger_, "Attempting to connect");
Socket_->connect(Destination, Poco::Timespan(100, 0));
Socket_->completeHandshake();
if (!Server_.allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
*this, &RADSEC_server::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
*this, &RADSEC_server::onError));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
*this, &RADSEC_server::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (...) {
poco_information(Logger_, "Could not connect.");
}
}
return false;
}
inline void Disconnect() {
if (Connected_) {
std::lock_guard G(LocalMutex_);
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
*this, &RADSEC_server::onData));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
*this, &RADSEC_server::onError));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
*this, &RADSEC_server::onShutdown));
Socket_->close();
Connected_ = false;
}
poco_information(Logger_, "Disconnecting.");
}
static void DecodeFile(const std::string &filename, const std::string &s) {
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
std::ios_base::binary);
std::stringstream is(s);
Poco::Base64Decoder ds(is);
Poco::StreamCopier::copyStream(ds, sec_file);
sec_file.close();
}
[[nodiscard]] inline std::string CommonName() {
if (Peer_Cert_)
return Peer_Cert_->commonName();
return "";
}
[[nodiscard]] inline std::string IssuerName() {
if (Peer_Cert_)
return Peer_Cert_->issuerName();
return "";
}
[[nodiscard]] inline std::string SubjectName() {
if (Peer_Cert_)
return Peer_Cert_->subjectName();
return "";
}
private:
std::recursive_mutex LocalMutex_;
Poco::Net::SocketReactor &Reactor_;
GWObjects::RadiusProxyServerEntry Server_;
Poco::Logger &Logger_;
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
Poco::Thread ReconnectThread_;
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
volatile bool Connected_ = false;
volatile bool TryAgain_ = true;
};
} // namespace OpenWifi

View File

@@ -169,10 +169,12 @@ namespace OpenWifi::RESTAPI_RPC {
if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) {
// we need to post a kafka event for this.
if (Params.has(uCentralProtocol::CONFIG)) {
if (Params.has(uCentralProtocol::CONFIG) && Params.isObject(uCentralProtocol::CONFIG)) {
auto Config = Params.get(uCentralProtocol::CONFIG)
.extract<Poco::JSON::Object::Ptr>();
DeviceConfigurationChangeKafkaEvent KEvent(
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
Params.get(uCentralProtocol::CONFIG).toString());
Config);
}
}

View File

@@ -7,7 +7,6 @@
//
#include "Poco/Array.h"
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_default_configurations.h"
#include "StorageService.h"

View File

@@ -0,0 +1,117 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by stephane bourque on 2023-07-11.
// Arilia Wireless Inc.
//
#include "RESTAPI/RESTAPI_default_firmware.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "framework/orm.h"
#include "framework/ow_constants.h"
#include "framework/utils.h"
namespace OpenWifi {
void RESTAPI_default_firmware::DoGet() {
std::string deviceType = ORM::Escape(GetBinding(RESTAPI::Protocol::DEVICETYPE, ""));
GWObjects::DefaultFirmware Firmware;
if (StorageService()->GetDefaultFirmware(deviceType, Firmware)) {
return Object(Firmware);
}
NotFound();
}
void RESTAPI_default_firmware::DoDelete() {
std::string deviceType = ORM::Escape(GetBinding(RESTAPI::Protocol::DEVICETYPE, ""));
if (deviceType.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (StorageService()->DeleteDefaultFirmware(deviceType)) {
return OK();
}
BadRequest(RESTAPI::Errors::CouldNotBeDeleted);
}
void RESTAPI_default_firmware::DoPost() {
std::string deviceType = GetBinding(RESTAPI::Protocol::DEVICETYPE, "");
if (deviceType.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (StorageService()->DefaultFirmwareAlreadyExists(deviceType)) {
return BadRequest(RESTAPI::Errors::DefFirmwareNameExists);
}
const auto &Obj = ParsedBody_;
GWObjects::DefaultFirmware Firmware;
if (!Firmware.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(Firmware.uri.empty() || Firmware.revision.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
try {
Poco::URI FirmwareURI(Firmware.uri);
} catch (...) {
return BadRequest(RESTAPI::Errors::InvalidURI);
}
Firmware.Created = Firmware.LastModified = Utils::Now();
if (StorageService()->CreateDefaultFirmware(Firmware)) {
GWObjects::DefaultFirmware ModifiedFirmware;
StorageService()->GetDefaultFirmware(deviceType, ModifiedFirmware);
return Object(ModifiedFirmware);
}
BadRequest(RESTAPI::Errors::RecordNotCreated);
}
void RESTAPI_default_firmware::DoPut() {
std::string deviceType = GetBinding(RESTAPI::Protocol::DEVICETYPE, "");
const auto &Obj = ParsedBody_;
GWObjects::DefaultFirmware NewFirmware;
if (!NewFirmware.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
GWObjects::DefaultFirmware Existing;
if (!StorageService()->GetDefaultFirmware(deviceType, Existing)) {
return NotFound();
}
Existing.LastModified = Utils::Now();
AssignIfPresent(Obj, "description", Existing.Description);
AssignIfPresent(Obj, "imageCreationDate", Existing.imageCreationDate);
AssignIfPresent(Obj, "revision", Existing.revision);
if (Obj->has("uri")) {
if(NewFirmware.uri.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
try {
Poco::URI FirmwareURI(NewFirmware.uri);
} catch (...) {
return BadRequest(RESTAPI::Errors::InvalidURI);
}
Existing.uri = NewFirmware.uri;
}
if (StorageService()->UpdateDefaultFirmware(Existing)) {
GWObjects::DefaultFirmware ModifiedFirmware;
StorageService()->GetDefaultFirmware(deviceType, ModifiedFirmware);
return Object(ModifiedFirmware);
}
BadRequest(RESTAPI::Errors::RecordNotUpdated);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,30 @@
//
// Created by stephane bourque on 2023-07-11.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
class RESTAPI_default_firmware : public RESTAPIHandler {
public:
RESTAPI_default_firmware(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server,
uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() {
return std::list<std::string>{"/api/v1/default_firmware/{deviceType}"};
}
void DoGet() final;
void DoDelete() final;
void DoPost() final;
void DoPut() final;
};
} // namespace OpenWifi

View File

@@ -0,0 +1,25 @@
//
// Created by stephane bourque on 2023-07-11.
//
#include "RESTAPI_default_firmwares.h"
#include "Poco/Array.h"
#include "RESTAPI_default_firmwares.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
namespace OpenWifi {
void RESTAPI_default_firmwares::DoGet() {
if (QB_.CountOnly) {
auto Count = StorageService()->GetDefaultFirmwaresCount();
return ReturnCountOnly(Count);
}
std::vector<GWObjects::DefaultFirmware> Firmwares;
StorageService()->GetDefaultFirmwares(QB_.Offset, QB_.Limit, Firmwares);
return Object(RESTAPI::Protocol::FIRMWARES, Firmwares);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,25 @@
//
// Created by stephane bourque on 2023-07-11.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
class RESTAPI_default_firmwares : public RESTAPIHandler {
public:
RESTAPI_default_firmwares(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server,
uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/default_firmwares"}; }
void DoGet() final;
void DoDelete() final{};
void DoPost() final{};
void DoPut() final{};
};
} // namespace OpenWifi

View File

@@ -163,8 +163,11 @@ namespace OpenWifi {
{APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry,
30000ms},
{APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms},
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script,
300000ms}};
{APCommands::Commands::rrm, false, true, &RESTAPI_device_commandHandler::RRM, 60000ms},
{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms}
};
void RESTAPI_device_commandHandler::DoPost() {
if (!ValidateParameters()) {
@@ -1024,7 +1027,7 @@ namespace OpenWifi {
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::wifiscan, false, Cmd, Params,
*Request, *Response, timeout, nullptr, this, Logger_);
if (Cmd.ErrorCode == 0) {
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(Cmd.Results));
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, Cmd.Results);
}
}
@@ -1069,7 +1072,7 @@ namespace OpenWifi {
Logger_);
if (Cmd.ErrorCode == 0) {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
std::make_shared<std::string>(Cmd.Results));
Cmd.Results);
}
return;
}
@@ -1126,9 +1129,6 @@ namespace OpenWifi {
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
#define DBGLINE \
{ std::cout << __LINE__ << std::endl; }
void RESTAPI_device_commandHandler::Rtty(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
@@ -1342,4 +1342,163 @@ namespace OpenWifi {
}
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
void RESTAPI_device_commandHandler::RRM(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("RRM({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(!ParsedBody_->has("actions") || !ParsedBody_->isArray("actions")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
const auto &Actions = *ParsedBody_->getArray("actions");
// perform some validation on the commands.
for(const auto &action:Actions) {
auto ActionDetails = action.extract<Poco::JSON::Object::Ptr>();
if(!ActionDetails->has("action")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto ActionStr = ActionDetails->get("action").toString();
if( ActionStr != "kick"
&& ActionStr != "channel_switch"
&& ActionStr != "tx_power"
&& ActionStr != "beacon_request"
&& ActionStr != "bss_transition"
&& ActionStr != "neighbors" ) {
return BadRequest(RESTAPI::Errors::InvalidRRMAction);
}
}
Poco::JSON::Object Params;
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::ACTIONS, Actions);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::RRM;
std::ostringstream os;
Params.stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
Cmd.Status= "completed";
if(CommandManager()->FireAndForget(SerialNumber_, uCentralProtocol::RRM, Params)) {
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_COMPLETED);
Cmd.Status= "completed";
return OK();
}
Cmd.Status= "failed"; // should never happen
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_COMPLETED);
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
void RESTAPI_device_commandHandler::Transfer(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("TRANSFER({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::DeviceTransferRequest TR;
if(!TR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::TRANSFER;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::transfer, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
void RESTAPI_device_commandHandler::CertUpdate(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("CERTUPDATE({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::DeviceCertificateUpdateRequest CR;
if(!CR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::DeviceTransferRequest TR;
if(!TR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::CERTUPDATE;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::certupdate, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
} // namespace OpenWifi

View File

@@ -62,6 +62,12 @@ namespace OpenWifi {
const GWObjects::DeviceRestrictions &R);
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void RRM(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void CertUpdate(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void Transfer(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
static auto PathName() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

@@ -174,6 +174,13 @@ namespace OpenWifi {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(GetBoolParameter("simulatedDevices",false)) {
if(StorageService()->DeleteSimulatedDevice("")) {
return OK();
}
return NotFound();
}
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}

View File

@@ -8,6 +8,11 @@
namespace OpenWifi {
static bool ValidRadiusPoolServerType(const std::string &T) {
static std::set<std::string> Types{ "radsec", "generic", "orion", "globalreach"};
return Types.find(T)!=Types.end();
}
void RESTAPI_radiusProxyConfig_handler::DoGet() {
Logger_.information(fmt::format("GET-RADIUS-PROXY-CONFIG: TID={} user={} thr_id={}",
TransactionId_, Requester(),
@@ -44,10 +49,22 @@ namespace OpenWifi {
}
// Logically validate the config.
for (const auto &pool : C.pools) {
for (auto &pool : C.pools) {
if (pool.name.empty()) {
return BadRequest(RESTAPI::Errors::PoolNameInvalid);
}
if (pool.radsecPoolType.empty()) {
pool.radsecPoolType = "generic";
}
if(!ValidRadiusPoolServerType(pool.radsecPoolType)) {
return BadRequest(RESTAPI::Errors::NotAValidRadiusPoolType);
}
if(pool.radsecKeepAlive==0) {
pool.radsecKeepAlive=25;
}
for (const auto &config : {pool.acctConfig, pool.authConfig, pool.coaConfig}) {
if (config.servers.empty())
continue;

View File

@@ -110,14 +110,26 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(Parameters.callingStationId.empty() || Parameters.accountingSessionId.empty() || Parameters.accountingMultiSessionId.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto Command = GetParameter("operation","");
if(Command=="coadm") {
if(RADIUSSessionTracker()->SendCoADM(SerialNumber, Parameters.accountingSessionId)) {
if(Parameters.callingStationId.empty() || Parameters.accountingSessionId.empty() || Parameters.accountingMultiSessionId.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto Index = Parameters.accountingSessionId + Parameters.accountingMultiSessionId;
poco_information(Logger(), fmt::format("Disconnecting session {},{}", Parameters.accountingSessionId, Parameters.accountingMultiSessionId ));
if(RADIUSSessionTracker()->SendCoADM(SerialNumber, Index)) {
return OK();
}
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
if(Command=="disconnectUser" && !Parameters.userName.empty()) {
if(Parameters.userName.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
poco_information(Logger(), fmt::format("Disconnecting sessions for user: {}", Parameters.userName ));
if(RADIUSSessionTracker()->DisconnectUser(Parameters.userName)) {
return OK();
}
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);

View File

@@ -22,6 +22,8 @@
#include "RESTAPI/RESTAPI_scripts_handler.h"
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
#include "RESTAPI/RESTAPI_radiussessions_handler.h"
#include "RESTAPI/RESTAPI_default_firmware.h"
#include "RESTAPI/RESTAPI_default_firmwares.h"
#include "framework/RESTAPI_SystemCommand.h"
#include "framework/RESTAPI_SystemConfiguration.h"
@@ -41,7 +43,8 @@ namespace OpenWifi {
RESTAPI_blacklist, RESTAPI_blacklist_list, RESTAPI_iptocountry_handler,
RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_script_handler,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket, RESTAPI_radiussessions_handler,
RESTAPI_regulatory>(Path, Bindings, L, S,
RESTAPI_regulatory, RESTAPI_default_firmwares,
RESTAPI_default_firmware>(Path, Bindings, L, S,
TransactionId);
}
@@ -55,6 +58,7 @@ namespace OpenWifi {
RESTAPI_commands, RESTAPI_ouis, RESTAPI_file, RESTAPI_blacklist,
RESTAPI_iptocountry_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler,
RESTAPI_script_handler, RESTAPI_blacklist_list, RESTAPI_radiussessions_handler,
RESTAPI_regulatory>(Path, Bindings, L, S, TransactionId);
RESTAPI_regulatory, RESTAPI_default_firmwares,
RESTAPI_default_firmware>(Path, Bindings, L, S, TransactionId);
}
} // namespace OpenWifi

View File

@@ -59,6 +59,8 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "pendingUUID", pendingUUID);
field_to_json(Obj, "simulated", simulated);
field_to_json(Obj, "lastRecordedContact", lastRecordedContact);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "connectReason", connectReason);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -122,6 +124,8 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "pendingUUID", pendingUUID);
field_from_json(Obj, "simulated", simulated);
field_from_json(Obj, "lastRecordedContact", lastRecordedContact);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "connectReason", connectReason);
return true;
} catch (const Poco::Exception &E) {
}
@@ -171,6 +175,31 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "lastModified", LastModified);
}
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "deviceType", deviceType);
field_to_json(Obj, "description", Description);
field_to_json(Obj, "uri", uri);
field_to_json(Obj, "revision", revision);
field_to_json(Obj, "imageCreationDate", imageCreationDate);
field_to_json(Obj, "created", Created);
field_to_json(Obj, "lastModified", LastModified);
}
bool DefaultFirmware::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "deviceType", deviceType);
field_from_json(Obj, "description", Description);
field_from_json(Obj, "uri", uri);
field_from_json(Obj, "revision", revision);
field_from_json(Obj, "imageCreationDate", imageCreationDate);
field_from_json(Obj, "created", Created);
field_from_json(Obj, "lastModified", LastModified);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void CommandDetails::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("details", Obj, Details);
EmbedDocument("results", Obj, Results);
@@ -405,6 +434,10 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "acctConfig", acctConfig);
field_to_json(Obj, "coaConfig", coaConfig);
field_to_json(Obj, "useByDefault", useByDefault);
field_to_json(Obj, "radsecKeepAlive", radsecKeepAlive);
field_to_json(Obj, "poolProxyIp", poolProxyIp);
field_to_json(Obj, "radsecPoolType", radsecPoolType);
field_to_json(Obj, "enabled", enabled);
}
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -415,6 +448,10 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "acctConfig", acctConfig);
field_from_json(Obj, "coaConfig", coaConfig);
field_from_json(Obj, "useByDefault", useByDefault);
field_from_json(Obj, "radsecKeepAlive", radsecKeepAlive);
field_from_json(Obj, "poolProxyIp", poolProxyIp);
field_from_json(Obj, "radsecPoolType", radsecPoolType);
field_from_json(Obj, "enabled", enabled);
return true;
} catch (const Poco::Exception &E) {
}
@@ -633,18 +670,49 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "interface", interface);
field_to_json(Obj, "secret", secret);
field_to_json(Obj, "nasId", nasId);
field_to_json(Obj, "calledStationId", calledStationId);
}
void RADIUSSessionList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "sessions", sessions);
}
void RadiusCoADMParameters::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "accountingSessionId", accountingSessionId);
field_to_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
field_to_json(Obj, "callingStationId", callingStationId);
field_to_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
field_to_json(Obj, "userName", userName);
}
bool RadiusCoADMParameters::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "accountingSessionId", accountingSessionId);
field_from_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
field_from_json(Obj, "callingStationId", callingStationId);
field_from_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
field_from_json(Obj, "userName", userName);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceTransferRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "server", server);
field_from_json(Obj, "port", port);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceCertificateUpdateRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "encodedCertificate", encodedCertificate);
return true;
} catch (const Poco::Exception &E) {
}

View File

@@ -109,7 +109,9 @@ namespace OpenWifi::GWObjects {
DeviceRestrictions restrictionDetails;
std::uint64_t pendingUUID = 0;
bool simulated=false;
std::uint64_t lastRecordedContact=0;
std::uint64_t lastRecordedContact=0;
std::uint64_t certificateExpiryDate = 0;
std::string connectReason;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -182,6 +184,26 @@ namespace OpenWifi::GWObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DefaultFirmware {
std::string deviceType;
std::string Description;
std::string uri;
std::string revision;
uint64_t imageCreationDate;
uint64_t Created;
uint64_t LastModified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DefaultFirmwareList {
std::vector<DefaultFirmware> firmwares;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct CommandDetails {
std::string UUID;
std::string SerialNumber;
@@ -340,6 +362,10 @@ namespace OpenWifi::GWObjects {
RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig;
bool useByDefault = false;
std::string radsecPoolType;
std::string poolProxyIp;
std::uint64_t radsecKeepAlive=25;
bool enabled=true;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -403,6 +429,7 @@ namespace OpenWifi::GWObjects {
inputGigaWords = 0,
outputGigaWords = 0;
std::uint32_t sessionTime = 0;
std::string calledStationId;
#ifdef TIP_GATEWAY_SERVICE
RADIUS::RadiusPacket accountingPacket;
@@ -420,7 +447,68 @@ namespace OpenWifi::GWObjects {
std::string accountingSessionId,
accountingMultiSessionId,
callingStationId,
chargeableUserIdentity;
chargeableUserIdentity,
userName;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
enum class RadiusPoolStrategy {
round_robin, random, weighted, unknown
};
enum class RadiusEndpointType {
generic, radsec, globalreach, orion, unknown
};
static inline RadiusEndpointType RadiusEndpointType(const std::string &T) {
if(T=="generic") return RadiusEndpointType::generic;
if(T=="radsec") return RadiusEndpointType::radsec;
if(T=="globalreach") return RadiusEndpointType::globalreach;
if(T=="orion") return RadiusEndpointType::orion;
return RadiusEndpointType::unknown;
}
static inline RadiusPoolStrategy RadiusPoolStrategy(const std::string &T) {
if(T=="round_robin") return RadiusPoolStrategy::round_robin;
if(T=="random") return RadiusPoolStrategy::random;
if(T=="weighted") return RadiusPoolStrategy::weighted;
return RadiusPoolStrategy::unknown;
}
static inline std::string to_string(enum RadiusEndpointType T) {
switch(T) {
case RadiusEndpointType::generic: return "generic";
case RadiusEndpointType::radsec: return "radsec";
case RadiusEndpointType::globalreach: return "globalreach";
case RadiusEndpointType::orion: return "orion";
default:
return "unknown";
}
}
static inline std::string to_string(enum RadiusPoolStrategy T) {
switch(T) {
case RadiusPoolStrategy::round_robin: return "round_robin";
case RadiusPoolStrategy::random: return "random";
case RadiusPoolStrategy::weighted: return "weighted";
default:
return "unknown";
}
}
struct DeviceTransferRequest {
std::string serialNumber;
std::string server;
std::uint64_t port;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceCertificateUpdateRequest {
std::string serialNumber;
std::string encodedCertificate;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};

View File

@@ -78,21 +78,22 @@ namespace OpenWifi::OWLSObjects {
return false;
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "simulationId", simulationId);
field_to_json(Obj, "state", state);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "msgsTx", msgsTx);
field_to_json(Obj, "msgsRx", msgsRx);
field_to_json(Obj, "liveDevices", liveDevices);
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
field_to_json(Obj, "startTime", startTime);
field_to_json(Obj, "endTime", endTime);
field_to_json(Obj, "errorDevices", errorDevices);
field_to_json(Obj, "owner", owner);
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "simulationId", simulationId);
field_to_json(Obj, "state", state);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "msgsTx", msgsTx);
field_to_json(Obj, "msgsRx", msgsRx);
field_to_json(Obj, "liveDevices", liveDevices);
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
field_to_json(Obj, "startTime", startTime);
field_to_json(Obj, "endTime", endTime);
field_to_json(Obj, "errorDevices", errorDevices);
field_to_json(Obj, "owner", owner);
field_to_json(Obj, "expectedDevices", expectedDevices);
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {}

View File

@@ -43,23 +43,24 @@ namespace OpenWifi::OWLSObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
uint64_t expectedDevices;
void to_json(Poco::JSON::Object &Obj) const;
};
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
int O;

View File

@@ -1194,4 +1194,243 @@ namespace OpenWifi::ProvObjects {
return false;
}
void GLBLRAccountInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "privateKey", privateKey);
field_to_json(Obj, "country", country);
field_to_json(Obj, "province", province);
field_to_json(Obj, "city", city);
field_to_json(Obj, "organization", organization);
field_to_json(Obj, "commonName", commonName);
field_to_json(Obj, "CSR", CSR);
field_to_json(Obj, "CSRPrivateKey", CSRPrivateKey);
field_to_json(Obj, "CSRPublicKey", CSRPublicKey);
field_to_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
}
bool GLBLRAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "privateKey", privateKey);
field_from_json(Obj, "country", country);
field_from_json(Obj, "province", province);
field_from_json(Obj, "city", city);
field_from_json(Obj, "organization", organization);
field_from_json(Obj, "commonName", commonName);
field_from_json(Obj, "CSR", CSR);
field_from_json(Obj, "CSRPrivateKey", CSRPrivateKey);
field_from_json(Obj, "CSRPublicKey", CSRPublicKey);
field_from_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void GLBLRCertificateInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "name", name);
field_to_json(Obj, "accountId", accountId);
field_to_json(Obj, "csr", csr);
field_to_json(Obj, "certificate", certificate);
field_to_json(Obj, "certificateChain", certificateChain);
field_to_json(Obj, "certificateId", certificateId);
field_to_json(Obj, "expiresAt", expiresAt);
field_to_json(Obj, "created", created);
}
bool GLBLRCertificateInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "name", name);
field_from_json(Obj, "accountId", accountId);
field_from_json(Obj, "csr", csr);
field_from_json(Obj, "certificate", certificate);
field_from_json(Obj, "certificateChain", certificateChain);
field_from_json(Obj, "certificateId", certificateId);
field_from_json(Obj, "expiresAt", expiresAt);
field_from_json(Obj, "created", created);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void GooglOrionAccountInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "privateKey", privateKey);
field_to_json(Obj, "certificate", certificate);
field_to_json(Obj, "cacerts", cacerts);
}
bool GooglOrionAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "privateKey", privateKey);
field_from_json(Obj, "certificate", certificate);
field_from_json(Obj, "cacerts", cacerts);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSServer::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Hostname", Hostname);
field_to_json(Obj, "IP", IP);
field_to_json(Obj, "Port", Port);
field_to_json(Obj, "Secret", Secret);
}
bool RADIUSServer::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Hostname", Hostname);
field_from_json(Obj, "IP", IP);
field_from_json(Obj, "Port", Port);
field_from_json(Obj, "Secret", Secret);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPointRadiusType::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Authentication", Authentication);
field_to_json(Obj, "Accounting", Accounting);
field_to_json(Obj, "CoA", CoA);
field_to_json(Obj, "AccountingInterval", AccountingInterval);
}
bool RADIUSEndPointRadiusType::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Authentication", Authentication);
field_from_json(Obj, "Accounting", Accounting);
field_from_json(Obj, "CoA", CoA);
field_from_json(Obj, "AccountingInterval", AccountingInterval);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPointRadsecType::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Hostname", Hostname);
field_to_json(Obj, "IP", IP);
field_to_json(Obj, "Port", Port);
field_to_json(Obj, "Secret", Secret);
field_to_json(Obj, "OpenRoamingType", OpenRoamingType);
field_to_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
field_to_json(Obj, "Weight", Weight);
field_to_json(Obj, "Certificate", Certificate);
field_to_json(Obj, "PrivateKey", PrivateKey);
field_to_json(Obj, "CaCerts", CaCerts);
field_to_json(Obj, "AllowSelfSigned", AllowSelfSigned);
}
bool RADIUSEndPointRadsecType::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Hostname", Hostname);
field_from_json(Obj, "IP", IP);
field_from_json(Obj, "Port", Port);
field_from_json(Obj, "Secret", Secret);
field_from_json(Obj, "OpenRoamingType", OpenRoamingType);
field_from_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
field_from_json(Obj, "Weight", Weight);
field_from_json(Obj, "Certificate", Certificate);
field_from_json(Obj, "PrivateKey", PrivateKey);
field_from_json(Obj, "CaCerts", CaCerts);
field_from_json(Obj, "AllowSelfSigned", AllowSelfSigned);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPoint::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "Type", Type);
field_to_json(Obj, "RadsecServers", RadsecServers);
field_to_json(Obj, "RadiusServers", RadiusServers);
field_to_json(Obj, "PoolStrategy", PoolStrategy);
field_to_json(Obj, "Index", Index);
field_to_json(Obj, "UsedBy", UsedBy);
field_to_json(Obj, "UseGWProxy", UseGWProxy);
field_to_json(Obj, "NasIdentifier", NasIdentifier);
field_to_json(Obj, "AccountingInterval", AccountingInterval);
}
bool RADIUSEndPoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "Type", Type);
field_from_json(Obj, "RadsecServers", RadsecServers);
field_from_json(Obj, "RadiusServers", RadiusServers);
field_from_json(Obj, "PoolStrategy", PoolStrategy);
field_from_json(Obj, "Index", Index);
field_from_json(Obj, "UsedBy", UsedBy);
field_from_json(Obj, "UseGWProxy", UseGWProxy);
field_from_json(Obj, "NasIdentifier", NasIdentifier);
field_from_json(Obj, "AccountingInterval", AccountingInterval);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndpointUpdateStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "lastUpdate", lastUpdate);
field_to_json(Obj, "lastConfigurationChange", lastConfigurationChange);
}
bool RADIUSEndpointUpdateStatus::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "lastUpdate", lastUpdate);
field_from_json(Obj, "lastConfigurationChange", lastConfigurationChange);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::Read() {
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
try {
if (F.exists()) {
Poco::JSON::Parser P;
std::ifstream ifs(F.path(), std::ios_base::in | std::ios_base::binary);
auto Obj = P.parse(ifs);
return from_json(Obj.extract<Poco::JSON::Object::Ptr>());
}
} catch (...) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::Save() {
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
try {
Poco::JSON::Object Obj;
to_json(Obj);
std::ofstream O(F.path(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
Poco::JSON::Stringifier::stringify(Obj, O);
return true;
} catch (...) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::ChangeConfiguration() {
Read();
lastConfigurationChange = Utils::Now();
return Save();
}
} // namespace OpenWifi::ProvObjects

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
#pragma once
#include <fstream>
#include <shared_mutex>
#include <mutex>
#include "framework/MicroServiceFuncs.h"
#include "framework/SubSystemServer.h"
@@ -38,7 +38,7 @@ namespace OpenWifi {
inline int Start() final {
poco_notice(Logger(), "Starting...");
std::shared_lock L(KeyMutex_);
std::lock_guard L(KeyMutex_);
CacheFilename_ = MicroServiceDataDirectory() + "/signature_cache";
Poco::File CacheFile(CacheFilename_);
@@ -91,7 +91,7 @@ namespace OpenWifi {
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
const std::string &Data) const {
std::shared_lock L(KeyMutex_);
std::lock_guard L(KeyMutex_);
try {
if (Restrictions.key_info.algo == "static") {
return "aaaaaaaaaa";
@@ -120,7 +120,7 @@ namespace OpenWifi {
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
const Poco::URI &uri) {
std::shared_lock L(KeyMutex_);
std::lock_guard L(KeyMutex_);
try {
if (Restrictions.key_info.algo == "static") {
return "aaaaaaaaaa";
@@ -172,7 +172,7 @@ namespace OpenWifi {
}
private:
mutable std::shared_mutex KeyMutex_;
mutable std::mutex KeyMutex_;
std::map<std::string, Poco::SharedPtr<Poco::Crypto::RSAKey>> Keys_;
std::map<std::string, std::string> SignatureCache_;
std::string CacheFilename_;

View File

@@ -175,6 +175,19 @@ namespace OpenWifi {
uint64_t GetDefaultConfigurationsCount();
bool DefaultConfigurationAlreadyExists(std::string &Name);
bool UpdateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware);
bool CreateDefaultFirmware(GWObjects::DefaultFirmware &DefConfig);
bool DeleteDefaultFirmware(std::string &name);
bool GetDefaultFirmware(std::string &name, GWObjects::DefaultFirmware &DefConfig);
bool GetDefaultFirmwares(uint64_t From, uint64_t HowMany,
std::vector<GWObjects::DefaultFirmware> &Devices);
bool FindDefaultFirmwareForModel(const std::string &Model,
GWObjects::DefaultFirmware &DefConfig);
uint64_t GetDefaultFirmwaresCount();
bool DefaultFirmwareAlreadyExists(std::string &Name);
bool AddCommand(std::string &SerialNumber, GWObjects::CommandDetails &Command,
CommandExecutionType Type);
bool GetCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
@@ -224,6 +237,8 @@ namespace OpenWifi {
bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
uint64_t GetBlackListDeviceCount();
bool DeleteSimulatedDevice(const std::string &SerialNumber);
bool RemoveHealthChecksRecordsOlderThan(uint64_t Date);
bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date);
bool RemoveStatisticsRecordsOlderThan(uint64_t Date);
@@ -242,6 +257,7 @@ namespace OpenWifi {
int Create_CommandList();
int Create_BlackList();
int Create_FileUploads();
int Create_DefaultFirmwares();
bool AnalyzeCommands(Types::CountedMap &R);
bool AnalyzeDevices(GWObjects::Dashboard &D);

View File

@@ -0,0 +1,66 @@
//
// Created by stephane bourque on 2023-07-12.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/ExpireLRUCache.h"
#include "sdks/sdk_fms.h"
namespace OpenWifi {
class FirmwareRevisionCache : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new FirmwareRevisionCache;
return instance_;
}
inline int Start() override {
poco_notice(Logger(), "Starting...");
return 0;
}
inline void Stop() override {
poco_notice(Logger(), "Stopping...");
poco_notice(Logger(), "Stopped...");
}
inline bool DeviceMustUpgrade([[maybe_unused]] std::string &deviceType,
[[maybe_unused]] const std::string &firmware_string,
[[maybe_unused]] GWObjects::DefaultFirmware &Firmware) {
return false;
if(StorageService()->GetDefaultFirmware(deviceType,Firmware)) {
std::string key{ deviceType + Firmware.revision };
if(!Cache_.has(key)) {
FMSObjects::FirmwareAgeDetails FAD;
if(SDK::FMS::GetFirmwareAge(deviceType,Firmware.revision,FAD,Logger())) {
Cache_.add(key,FAD);
} else {
// if we cannot establish the age of the currently running firmware,
// then we assume it is too old.
return true;
}
}
auto FAD = Cache_.get(key);
if(FAD->imageDate < Firmware.imageCreationDate) {
return true;
}
}
return false;
}
private:
Poco::ExpireLRUCache<std::string, FMSObjects::FirmwareAgeDetails> Cache_{
512, 1200000};
FirmwareRevisionCache() noexcept
: SubSystemServer("FirmwareRevisionCache", "FWCACHE-SVR", "firmwarecache") {
}
};
inline auto FirmwareRevisionCache() { return FirmwareRevisionCache::instance(); }
} // namespace OpenWifi

View File

@@ -26,7 +26,7 @@ namespace OpenWifi {
Response.set("Connection", "keep-alive");
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
std::ostream &Answer = Response.send();
Answer << "process Alive and kicking!";
Answer << ALBHealthCheckServer()->CallbackText();
} catch (...) {
}
}

View File

@@ -37,6 +37,8 @@ namespace OpenWifi {
inline static std::atomic_uint64_t req_id_ = 1;
};
typedef std::string ALBHealthMessageCallback();
class ALBHealthCheckServer : public SubSystemServer {
public:
ALBHealthCheckServer();
@@ -48,10 +50,22 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
inline void RegisterExtendedHealthMessage(ALBHealthMessageCallback *F) {
Callback_=F;
};
inline std::string CallbackText() {
if(Callback_== nullptr) {
return "process Alive and kicking!";
} else {
return Callback_();
}
}
private:
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
ALBHealthMessageCallback *Callback_= nullptr;
int Port_ = 0;
mutable std::atomic_bool Running_ = false;
};

View File

@@ -11,10 +11,12 @@
#include "Poco/File.h"
#include "Poco/StreamCopier.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "framework/MicroServiceFuncs.h"
#include "nlohmann/json.hpp"
// #include "nlohmann/json.hpp"
namespace OpenWifi {
@@ -28,11 +30,11 @@ namespace OpenWifi {
if (F.exists()) {
std::ostringstream OS;
std::ifstream IF(FileName);
Poco::StreamCopier::copyStream(IF, OS);
Registry_ = nlohmann::json::parse(OS.str());
Poco::JSON::Parser P;
Registry_ = P.parse(IF).extract<Poco::JSON::Object::Ptr>();
}
} catch (...) {
Registry_ = nlohmann::json::parse("{}");
Registry_ = Poco::makeShared<Poco::JSON::Object>();
}
}
@@ -44,54 +46,47 @@ namespace OpenWifi {
inline ~AppServiceRegistry() { Save(); }
inline void Save() {
std::istringstream IS(to_string(Registry_));
std::ofstream OF;
OF.open(FileName, std::ios::binary | std::ios::trunc);
Poco::StreamCopier::copyStream(IS, OF);
Registry_->stringify(OF);
}
inline void Set(const char *Key, uint64_t Value) {
Registry_[Key] = Value;
void Set(const char *key, const std::vector<std::string> &V) {
Poco::JSON::Array Arr;
for(const auto &s:V) {
Arr.add(s);
}
Registry_->set(key,Arr);
Save();
}
template<class T> void Set(const char *key, const T &Value) {
Registry_->set(key,Value);
Save();
}
inline void Set(const char *Key, const std::string &Value) {
Registry_[Key] = Value;
Save();
}
bool Get(const char *key, std::vector<std::string> &Value) {
if(Registry_->has(key) && !Registry_->isNull(key) && Registry_->isArray(key)) {
auto Arr = Registry_->get(key);
for(const auto &v:Arr) {
Value.emplace_back(v);
}
return true;
}
return false;
}
inline void Set(const char *Key, bool Value) {
Registry_[Key] = Value;
Save();
}
inline bool Get(const char *Key, bool &Value) {
if (Registry_[Key].is_boolean()) {
Value = Registry_[Key].get<bool>();
return true;
}
return false;
}
inline bool Get(const char *Key, uint64_t &Value) {
if (Registry_[Key].is_number_unsigned()) {
Value = Registry_[Key].get<uint64_t>();
return true;
}
return false;
}
inline bool Get(const char *Key, std::string &Value) {
if (Registry_[Key].is_string()) {
Value = Registry_[Key].get<std::string>();
return true;
}
return false;
}
template<class T> bool Get(const char *key, T &Value) {
if(Registry_->has(key) && !Registry_->isNull(key)) {
Value = Registry_->getValue<T>(key);
return true;
}
return false;
}
private:
std::string FileName;
nlohmann::json Registry_;
Poco::JSON::Object::Ptr Registry_;
};
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }

View File

@@ -34,6 +34,10 @@ static std::string DefaultUCentralSchema = R"foo(
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"strict": {
"type": "boolean",
"default": false
},
"uuid": {
"type": "integer"
},
@@ -114,6 +118,20 @@ static std::string DefaultUCentralSchema = R"foo(
"random-password": {
"type": "boolean",
"default": false
},
"beacon-advertisement": {
"type": "object",
"properties": {
"device-name": {
"type": "boolean"
},
"device-serial": {
"type": "boolean"
},
"network-id": {
"type": "integer"
}
}
}
}
},
@@ -222,6 +240,52 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"interface.ssid.encryption": {
"type": "object",
"properties": {
"proto": {
"type": "string",
"enum": [
"none",
"owe",
"owe-transition",
"psk",
"psk2",
"psk-mixed",
"psk2-radius",
"wpa",
"wpa2",
"wpa-mixed",
"sae",
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
],
"examples": [
"psk2"
]
},
"key": {
"type": "string",
"maxLength": 63,
"minLength": 8
},
"ieee80211w": {
"type": "string",
"enum": [
"disabled",
"optional",
"required"
],
"default": "disabled"
},
"key-caching": {
"type": "boolean",
"default": true
}
}
},
"definitions": {
"type": "object",
"properties": {
@@ -716,7 +780,8 @@ static std::string DefaultUCentralSchema = R"foo(
"type": "string",
"enum": [
"dynamic",
"static"
"static",
"none"
],
"examples": [
"static"
@@ -1006,52 +1071,6 @@ static std::string DefaultUCentralSchema = R"foo(
}
]
},
"interface.ssid.encryption": {
"type": "object",
"properties": {
"proto": {
"type": "string",
"enum": [
"none",
"owe",
"owe-transition",
"psk",
"psk2",
"psk-mixed",
"psk2-radius",
"wpa",
"wpa2",
"wpa-mixed",
"sae",
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
],
"examples": [
"psk2"
]
},
"key": {
"type": "string",
"maxLength": 63,
"minLength": 8
},
"ieee80211w": {
"type": "string",
"enum": [
"disabled",
"optional",
"required"
],
"default": "disabled"
},
"key-caching": {
"type": "boolean",
"default": true
}
}
},
"interface.ssid.multi-psk": {
"type": "object",
"properties": {
@@ -2020,6 +2039,11 @@ static std::string DefaultUCentralSchema = R"foo(
"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.",
"type": "string"
},
"tip-information-element": {
"decription": "The device will broadcast the TIP vendor IE inside its beacons if this option is enabled.",
"type": "boolean",
"default": true
},
"fils-discovery-interval": {
"type": "integer",
"default": 20,
@@ -2235,6 +2259,17 @@ static std::string DefaultUCentralSchema = R"foo(
]
}
},
"vlan-awareness": {
"type": "object",
"properties": {
"first": {
"type": "integer"
},
"last": {
"type": "integer"
}
}
},
"vlan": {
"$ref": "#/$defs/interface.vlan"
},
@@ -2432,6 +2467,24 @@ static std::string DefaultUCentralSchema = R"foo(
"type": "boolean",
"default": false
},
"mode": {
"type": "string",
"enum": [
"radius",
"user"
]
},
"port-filter": {
"type": "array",
"items": {
"type": "string",
"examples": [
{
"LAN1": null
}
]
}
},
"server-certificate": {
"type": "string"
},
@@ -2443,6 +2496,77 @@ static std::string DefaultUCentralSchema = R"foo(
"items": {
"$ref": "#/$defs/interface.ssid.radius.local-user"
}
},
"radius": {
"type": "object",
"properties": {
"nas-identifier": {
"type": "string"
},
"auth-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1812
]
},
"auth-server-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1813
]
},
"acct-server-secret": {
"type": "string",
"examples": [
"secret"
]
},
"coa-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"coa-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1814
]
},
"coa-server-secret": {
"type": "string",
"examples": [
"secret"
]
}
}
}
}
},
@@ -2766,6 +2890,12 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"classifier": {
"type": "array",
"items": {
@@ -3008,6 +3138,24 @@ static std::string DefaultUCentralSchema = R"foo(
"relay-server": {
"type": "string",
"format": "uc-ip"
},
"circuit-id-format": {
"type": "string",
"enum": [
"vlan-id",
"ap-mac",
"ssid"
],
"default": "vlan-id"
},
"remote-id-format": {
"type": "string",
"enum": [
"vlan-id",
"ap-mac",
"ssid"
],
"default": "ap-mac"
}
}
}

View File

@@ -14,18 +14,18 @@ namespace OpenWifi {
void EventBusManager::run() {
Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
auto Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
false);
while (Running_) {
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
if (!Running_)
break;
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
Msg, false);
}
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
false);
};

View File

@@ -6,6 +6,7 @@
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
#include "cppkafka/utils/consumer_dispatcher.h"
namespace OpenWifi {
@@ -99,9 +100,12 @@ namespace OpenWifi {
try {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
Producer.produce(cppkafka::MessageBuilder(Msg->Topic())
.key(Msg->Key())
.payload(Msg->Payload()));
auto NewMessage = cppkafka::MessageBuilder(Msg->Topic());
NewMessage.key(Msg->Key());
NewMessage.partition(0);
NewMessage.payload(Msg->Payload());
Producer.produce(NewMessage);
Producer.flush();
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,
@@ -156,43 +160,49 @@ namespace OpenWifi {
}
});
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 20);
// bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
// auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 100);
Types::StringVec Topics;
KafkaManager()->Topics(Topics);
std::for_each(Topics_.begin(),Topics_.end(),
[&](const std::string & T) { Topics.emplace_back(T); });
Consumer.subscribe(Topics);
Running_ = true;
while (Running_) {
try {
std::vector<cppkafka::Message> MsgVec =
Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
for (auto const &Msg : MsgVec) {
if (!Msg)
continue;
if (Msg.get_error()) {
if (!Msg.is_eof()) {
poco_error(Logger_,
fmt::format("Error: {}", Msg.get_error().to_string()));
std::vector<cppkafka::Message> MsgVec;
Dispatcher_ = std::make_unique<cppkafka::ConsumerDispatcher>(Consumer);
Dispatcher_->run(
// Callback executed whenever a new message is consumed
[&](cppkafka::Message msg) {
// Print the key (if any)
std::lock_guard G(ConsumerMutex_);
auto It = Notifiers_.find(msg.get_topic());
if (It != Notifiers_.end()) {
const auto &FL = It->second;
for (const auto &[CallbackFunc, _] : FL) {
try {
CallbackFunc(msg.get_key(), msg.get_payload());
} catch(const Poco::Exception &E) {
} catch(...) {
}
if (!AutoCommit)
Consumer.async_commit(Msg);
continue;
}
KafkaManager()->Dispatch(Msg.get_topic().c_str(), Msg.get_key(), std::make_shared<std::string>(Msg.get_payload()));
if (!AutoCommit)
Consumer.async_commit(Msg);
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,
fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_, "std::exception");
Consumer.commit(msg);
},
// Whenever there's an error (other than the EOF soft error)
[&Logger_](cppkafka::Error error) {
poco_warning(Logger_,fmt::format("Error: {}", error.to_string()));
},
// Whenever EOF is reached on a partition, print this
[&Logger_](cppkafka::ConsumerDispatcher::EndOfFile, const cppkafka::TopicPartition& topic_partition) {
poco_debug(Logger_,fmt::format("Partition {} EOF", topic_partition.get_partition()));
}
}
);
Consumer.unsubscribe();
poco_information(Logger_, "Stopped...");
}
@@ -213,14 +223,13 @@ namespace OpenWifi {
}
void KafkaProducer::Produce(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
const std::string &Payload) {
std::lock_guard G(Mutex_);
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
void KafkaConsumer::Start() {
if (!Running_) {
Running_ = true;
Worker_.start(*this);
}
}
@@ -228,29 +237,16 @@ namespace OpenWifi {
void KafkaConsumer::Stop() {
if (Running_) {
Running_ = false;
Worker_.wakeUp();
if(Dispatcher_) {
Dispatcher_->stop();
}
Worker_.join();
}
}
void KafkaDispatcher::Start() {
if (!Running_) {
Running_ = true;
Worker_.start(*this);
}
}
void KafkaDispatcher::Stop() {
if (Running_) {
Running_ = false;
Queue_.wakeUpAll();
Worker_.join();
}
}
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic,
std::uint64_t KafkaConsumer::RegisterTopicWatcher(const std::string &Topic,
Types::TopicNotifyFunction &F) {
std::lock_guard G(Mutex_);
std::lock_guard G(ConsumerMutex_);
auto It = Notifiers_.find(Topic);
if (It == Notifiers_.end()) {
Types::TopicNotifyFunctionList L;
@@ -259,11 +255,12 @@ namespace OpenWifi {
} else {
It->second.emplace(It->second.end(), std::make_pair(F, FunctionId_));
}
Topics_.insert(Topic);
return FunctionId_++;
}
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(Mutex_);
void KafkaConsumer::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(ConsumerMutex_);
auto It = Notifiers_.find(Topic);
if (It != Notifiers_.end()) {
Types::TopicNotifyFunctionList &L = It->second;
@@ -275,56 +272,17 @@ namespace OpenWifi {
}
}
void KafkaDispatcher::Dispatch(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if (It != Notifiers_.end()) {
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
}
void KafkaDispatcher::run() {
Poco::Logger &Logger_ =
Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
poco_information(Logger_, "Starting...");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("kafka:dispatch");
while (Note && Running_) {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
auto It = Notifiers_.find(Msg->Topic());
if (It != Notifiers_.end()) {
const auto &FL = It->second;
for (const auto &[CallbackFunc, _] : FL) {
CallbackFunc(Msg->Key(), Msg->Payload());
}
}
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_, "Stopped...");
}
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
T.clear();
for (const auto &[TopicName, _] : Notifiers_)
T.push_back(TopicName);
}
int KafkaManager::Start() {
if (!KafkaEnabled_)
return 0;
ConsumerThr_.Start();
ProducerThr_.Start();
Dispatcher_.Start();
return 0;
}
void KafkaManager::Stop() {
if (KafkaEnabled_) {
poco_information(Logger(), "Stopping...");
Dispatcher_.Stop();
ProducerThr_.Stop();
ConsumerThr_.Stop();
poco_information(Logger(), "Stopped...");
@@ -333,39 +291,26 @@ namespace OpenWifi {
}
void KafkaManager::PostMessage(const char *topic, const std::string &key,
const std::shared_ptr<std::string> PayLoad, bool WrapMessage) {
const std::string & PayLoad, bool WrapMessage) {
if (KafkaEnabled_) {
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
}
}
void KafkaManager::Dispatch(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
Dispatcher_.Dispatch(Topic, Key, Payload);
}
[[nodiscard]] const std::shared_ptr<std::string> KafkaManager::WrapSystemId(const std::shared_ptr<std::string> PayLoad) {
*PayLoad = SystemInfoWrapper_ + *PayLoad + "}";
return PayLoad;
}
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic,
Types::TopicNotifyFunction &F) {
void KafkaManager::PostMessage(const char *topic, const std::string &key,
const Poco::JSON::Object &Object, bool WrapMessage) {
if (KafkaEnabled_) {
return Dispatcher_.RegisterTopicWatcher(Topic, F);
} else {
return 0;
std::ostringstream ObjectStr;
Object.stringify(ObjectStr);
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(ObjectStr.str()) : ObjectStr.str());
}
}
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
if (KafkaEnabled_) {
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
return fmt::format( R"lit({{ "system" : {{ "id" : {}, "host" : "{}" }}, "payload" : {} }})lit",
MicroServiceID(), MicroServicePrivateEndPoint(), PayLoad ) ;
}
void KafkaManager::Topics(std::vector<std::string> &T) { Dispatcher_.Topics(T); }
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) {
poco_information(
Logger(), fmt::format("Partition assigned: {}...", partitions.front().get_partition()));

View File

@@ -6,7 +6,7 @@
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "Poco/JSON/Object.h"
#include "framework/KafkaTopics.h"
#include "framework/OpenWifiTypes.h"
#include "framework/SubSystemServer.h"
@@ -18,17 +18,17 @@ namespace OpenWifi {
class KafkaMessage : public Poco::Notification {
public:
KafkaMessage(const char * Topic, const std::string &Key, const std::shared_ptr<std::string> Payload)
: Topic_(Topic), Key_(Key), Payload_(std::move(Payload)) {}
KafkaMessage(const char * Topic, const std::string &Key, const std::string &Payload)
: Topic_(Topic), Key_(Key), Payload_(Payload) {}
inline const char * Topic() { return Topic_; }
inline const std::string &Key() { return Key_; }
inline const std::string &Payload() { return *Payload_; }
inline const std::string &Payload() { return Payload_; }
private:
const char *Topic_;
std::string Key_;
std::shared_ptr<std::string> Payload_;
std::string Payload_;
};
class KafkaProducer : public Poco::Runnable {
@@ -36,10 +36,10 @@ namespace OpenWifi {
void run() override;
void Start();
void Stop();
void Produce(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
void Produce(const char *Topic, const std::string &Key, const std::string & Payload);
private:
std::recursive_mutex Mutex_;
std::mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
Poco::NotificationQueue Queue_;
@@ -47,33 +47,22 @@ namespace OpenWifi {
class KafkaConsumer : public Poco::Runnable {
public:
void run() override;
void Start();
void Stop();
private:
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
std::mutex ConsumerMutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
};
uint64_t FunctionId_ = 1;
std::unique_ptr<cppkafka::ConsumerDispatcher> Dispatcher_;
std::set<std::string> Topics_;
class KafkaDispatcher : public Poco::Runnable {
public:
void Start();
void Stop();
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void run() override;
friend class KafkaManager;
std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, int Id);
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
void run() override;
void Topics(std::vector<std::string> &T);
private:
std::recursive_mutex Mutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
uint64_t FunctionId_ = 1;
Poco::NotificationQueue Queue_;
};
class KafkaManager : public SubSystemServer {
@@ -92,20 +81,24 @@ namespace OpenWifi {
void Stop() override;
void PostMessage(const char *topic, const std::string &key,
const std::shared_ptr<std::string> PayLoad, bool WrapMessage = true);
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
[[nodiscard]] const std::shared_ptr<std::string> WrapSystemId(const std::shared_ptr<std::string> PayLoad);
const std::string &PayLoad, bool WrapMessage = true);
void PostMessage(const char *topic, const std::string &key,
const Poco::JSON::Object &Object, bool WrapMessage = true);
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
void Topics(std::vector<std::string> &T);
inline std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
return ConsumerThr_.RegisterTopicWatcher(Topic,F);
}
inline void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
return ConsumerThr_.UnregisterTopicWatcher(Topic,Id);
}
private:
bool KafkaEnabled_ = false;
std::string SystemInfoWrapper_;
KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
KafkaDispatcher Dispatcher_;
void PartitionAssignment(const cppkafka::TopicPartitionList &partitions);
void PartitionRevocation(const cppkafka::TopicPartitionList &partitions);

View File

@@ -20,6 +20,7 @@ namespace OpenWifi::KafkaTopics {
inline const char * DEVICE_EVENT_QUEUE = "device_event_queue";
inline const char * DEVICE_TELEMETRY = "device_telemetry";
inline const char * PROVISIONING_CHANGE = "provisioning_change";
inline const char * RRM = "rrm";
namespace ServiceEvents {
inline const char * EVENT_JOIN = "join";

View File

@@ -129,6 +129,8 @@ namespace OpenWifi {
}
} else {
poco_error(logger(), "Bad bus message.");
std::ostringstream os;
Object->stringify(std::cout);
}
auto i = Services_.begin();

View File

@@ -5,6 +5,8 @@
#include "framework/MicroServiceFuncs.h"
#include "framework/MicroService.h"
#include "framework/ALBserver.h"
namespace OpenWifi {
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
@@ -123,4 +125,12 @@ namespace OpenWifi {
return MicroService::instance().AllowExternalMicroServices();
}
void MicroServiceALBCallback( std::string Callback()) {
return ALBHealthCheckServer()->RegisterExtendedHealthMessage(Callback);
}
std::string MicroServiceAccessKey() {
return MicroService::instance().Hash();
}
} // namespace OpenWifi

View File

@@ -22,6 +22,7 @@ namespace OpenWifi {
std::string MicroServicePublicEndPoint();
std::string MicroServiceConfigGetString(const std::string &Key,
const std::string &DefaultValue);
std::string MicroServiceAccessKey();
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
std::string MicroServicePrivateEndPoint();
@@ -53,4 +54,5 @@ namespace OpenWifi {
std::string MicroServiceGetPublicAPIEndPoint();
void MicroServiceDeleteOverrideConfiguration();
bool AllowExternalMicroServices();
void MicroServiceALBCallback( std::string Callback());
} // namespace OpenWifi

View File

@@ -28,6 +28,9 @@ namespace OpenWifi::Types {
typedef std::string UUID_t;
typedef std::vector<UUID_t> UUIDvec_t;
typedef std::map<std::string, std::map<uint32_t, uint64_t>> Counted3DMapSII;
typedef std::vector<int64_t> IntList;
typedef std::vector<uint64_t> UIntList;
typedef std::vector<double> DoubleList;
struct MicroServiceMeta {
uint64_t Id = 0;

View File

@@ -574,7 +574,37 @@ namespace OpenWifi {
Poco::JSON::Stringifier::stringify(Object, Answer);
}
inline void ReturnRawJSON(const std::string &json_doc) {
inline void ReturnObject(const std::vector<std::string> &Strings) {
Poco::JSON::Array Arr;
for(const auto &String:Strings) {
Arr.add(String);
}
std::ostringstream os;
Arr.stringify(os);
return ReturnRawJSON(os.str());
}
template<class T> void ReturnObject(const std::vector<T> &Objects) {
Poco::JSON::Array Arr;
for(const auto &Object:Objects) {
Poco::JSON::Object O;
Object.to_json(O);
Arr.add(O);
}
std::ostringstream os;
Arr.stringify(os);
return ReturnRawJSON(os.str());
}
template<class T> void ReturnObject(const T &Object) {
Poco::JSON::Object O;
Object.to_json(O);
std::ostringstream os;
O.stringify(os);
return ReturnRawJSON(os.str());
}
inline void ReturnRawJSON(const std::string &json_doc) {
PrepareResponse();
if (Request != nullptr) {
// can we compress ???

View File

@@ -24,50 +24,63 @@ namespace OpenWifi {
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/system"}; }
inline void DoGet() {
inline void DoGet() final {
std::string Arg;
if (HasParameter("command", Arg) && Arg == "info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
if (HasParameter("command", Arg)) {
if (Arg == "info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
for (const auto &i : SubSystems) {
auto Hosts = i->HostSize();
for (uint64_t j = 0; j < Hosts; ++j) {
auto CertFileName = i->Host(j).CertFile();
if (!CertFileName.empty()) {
Poco::File F1(CertFileName);
if (F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if (InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
for (const auto &i : SubSystems) {
auto Hosts = i->HostSize();
for (uint64_t j = 0; j < Hosts; ++j) {
auto CertFileName = i->Host(j).CertFile();
if (!CertFileName.empty()) {
Poco::File F1(CertFileName);
if (F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if (InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
}
}
}
}
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if (Arg == "extraConfiguration") {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
if (Arg == "resources") {
Poco::JSON::Object Answer;
Answer.set("numberOfFileDescriptors", Utils::get_open_fds());
std::uint64_t currRealMem, peakRealMem, currVirtMem, peakVirtMem;
Utils::getMemory(currRealMem, peakRealMem, currVirtMem, peakVirtMem);
Answer.set("currRealMem", currRealMem);
Answer.set("peakRealMem", peakRealMem);
Answer.set("currVirtMem", currVirtMem);
Answer.set("peakVirtMem", peakVirtMem);
return ReturnObject(Answer);
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if (GetBoolParameter("extraConfiguration")) {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
BadRequest(RESTAPI::Errors::InvalidCommand);
}

View File

@@ -102,6 +102,20 @@ namespace OpenWifi::RESTAPI_utils {
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::DoubleList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
A.add(i);
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::IntList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
A.add(i);
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::TagList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
@@ -284,6 +298,28 @@ namespace OpenWifi::RESTAPI_utils {
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
Types::DoubleList &Value) {
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for (const auto &i : *A) {
Value.push_back(i);
}
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
Types::IntList &Value) {
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for (const auto &i : *A) {
Value.push_back(i);
}
}
}
template <class T>
void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
std::vector<T> &Value) {

View File

@@ -22,9 +22,8 @@ namespace OpenWifi {
class StorageClass : public SubSystemServer {
public:
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {}
int Start() override {
inline int Start() override {
std::lock_guard Guard(Mutex_);
Logger().notice("Starting.");
@@ -40,17 +39,22 @@ namespace OpenWifi {
return 0;
}
void Stop() override { Pool_->shutdown(); }
inline void Stop() override { Pool_->shutdown(); }
DBType Type() const { return dbType_; };
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {
}
private:
inline int Setup_SQLite();
inline int Setup_MySQL();
inline int Setup_PostgreSQL();
protected:
std::unique_ptr<Poco::Data::SessionPool> Pool_;
protected:
std::shared_ptr<Poco::Data::SessionPool> Pool_;
Poco::Data::SQLite::Connector SQLiteConn_;
Poco::Data::PostgreSQL::Connector PostgresConn_;
Poco::Data::MySQL::Connector MySQLConn_;
@@ -81,7 +85,7 @@ namespace OpenWifi {
// Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
// (int)NumSessions,
// (int)IdleTime));
Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
Pool_ = std::make_shared<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
(int)NumSessions, (int)IdleTime);
return 0;
}
@@ -102,7 +106,7 @@ namespace OpenWifi {
";compress=true;auto-reconnect=true";
Poco::Data::MySQL::Connector::registerConnector();
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
Pool_ = std::make_shared<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
NumSessions, IdleTime);
return 0;
@@ -126,7 +130,7 @@ namespace OpenWifi {
" connect_timeout=" + ConnectionTimeout;
Poco::Data::PostgreSQL::Connector::registerConnector();
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
Pool_ = std::make_shared<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
NumSessions, IdleTime);
return 0;

View File

@@ -37,6 +37,7 @@ namespace OpenWifi {
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = cas_;
// P.securityLevel =
auto Context = Poco::AutoPtr<Poco::Net::Context>(
new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
@@ -53,7 +54,6 @@ namespace OpenWifi {
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
@@ -76,18 +76,18 @@ namespace OpenWifi {
L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
}
SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr);
SSL_CTX_set_verify(SSLCtx, level_==Poco::Net::Context::VERIFY_NONE ? SSL_VERIFY_NONE : SSL_VERIFY_PEER, nullptr);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
}
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
SSL_CTX_dane_enable(SSLCtx);
Context->enableSessionCache();
Context->setSessionCacheSize(0);
Context->setSessionTimeout(60);
Context->enableExtendedCertificateVerification(true);
Context->enableExtendedCertificateVerification( level_!= Poco::Net::Context::VERIFY_NONE );
Context->disableStatelessSessionResumption();
}

View File

@@ -40,6 +40,7 @@ namespace OpenWifi {
};
}
#define DBGLINE std::cout << __LINE__ << ":" << __FILE__ << ", " << __func__ << std::endl;
namespace OpenWifi::RESTAPI::Errors {
struct msg {
uint64_t err_num;
@@ -401,6 +402,37 @@ namespace OpenWifi::RESTAPI::Errors {
1171, "Command not supported on simulated device."
};
static const struct msg VenuesNameAlreadyExists {
1172, "The venue name already exists."
};
static const struct msg InvalidGlobalReachAccount {
1173, "Invalid Global Reach account information."
};
static const struct msg CannotCreateCSR {
1174, "Cannot create a CSR certificate."
};
static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." };
static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." };
static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." };
static const struct msg InvalidRadiusTypeEndpoint { 1178, "Invalid RADIUS Server Endpoint type." };
static const struct msg InvalidRadiusEndpointPoolStrategy { 1179, "Invalid RADIUS Server Endpoint Pool strategy." };
static const struct msg EndpointMustHaveOneTypeOfServers { 1180, "All servers must be either RADIUS or RADSEC." };
static const struct msg RadiusEndpointIndexInvalid { 1181, "Index must be an address between 0.0.1.1 and 0.0.2.254" };
static const struct msg RadiusEndpointIndexMustBeUnique { 1182, "Index must be unique." };
static const struct msg OrionAccountMustExist { 1183, "Orion account must exist." };
static const struct msg GlobalReachCertMustExist { 1184, "Global Reach certificate must exist." };
static const struct msg InvalidRadsecMainCertificate { 1185, "Invalid Radsec main certificate." };
static const struct msg InvalidRadsecCaCertificate { 1186, "Invalid Radsec CA certificates." };
static const struct msg InvalidRadsecPrivteKey { 1187, "Invalid Radsec Private key." };
static const struct msg InvalidRadsecIPAddress { 1188, "Invalid Radsec IP Address." };
static const struct msg InvalidRadsecPort { 1189, "Invalid Radsec Port." };
static const struct msg InvalidRadsecSecret { 1190, "Invalid Radsec Secret." };
static const struct msg InvalidRadiusServer { 1191, "Invalid Radius Server." };
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
};
@@ -531,6 +563,10 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char *CONTENTDISPOSITION = "Content-Disposition";
static const char *CONTENTTYPE = "Content-Type";
static const char *TRANSFER = "transfer";
static const char *CERTUPDATE = "certupdate";
static const char *RRM = "rrm";
static const char *REQUIREMENTS = "requirements";
static const char *PASSWORDPATTERN = "passwordPattern";
static const char *ACCESSPOLICY = "accessPolicy";
@@ -648,6 +684,12 @@ namespace OpenWifi::uCentralProtocol {
static const char *RADIUSCOA = "coa";
static const char *RADIUSDST = "dst";
static const char *IES = "ies";
static const char *TRANSFER = "transfer";
static const char *CERTUPDATE = "certupdate";
static const char *RRM = "rrm";
static const char *ACTIONS = "actions";
} // namespace OpenWifi::uCentralProtocol
namespace OpenWifi::uCentralProtocol::Events {
@@ -740,6 +782,9 @@ namespace OpenWifi::APCommands {
telemetry,
ping,
script,
rrm,
certupdate,
transfer,
unknown
};
@@ -752,7 +797,10 @@ namespace OpenWifi::APCommands {
RESTAPI::Protocol::LEDS, RESTAPI::Protocol::TRACE,
RESTAPI::Protocol::REQUEST, RESTAPI::Protocol::WIFISCAN,
RESTAPI::Protocol::EVENTQUEUE, RESTAPI::Protocol::TELEMETRY,
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT};
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
RESTAPI::Protocol::TRANSFER
};
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }

View File

@@ -3,10 +3,19 @@
//
#include "Poco/Path.h"
#include "Poco/TemporaryFile.h"
#include "Poco/Crypto/ECKey.h"
#include "framework/AppServiceRegistry.h"
#include "framework/utils.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <algorithm>
#include <resolv.h>
namespace OpenWifi::Utils {
bool NormalizeMac(std::string &Mac) {
@@ -132,6 +141,15 @@ namespace OpenWifi::Utils {
return std::regex_match(Hostname, HostNameRegex);
}
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned)
{
static std::regex IntRegex("^-?[0-9]\\d*(\\.\\d+)?$");
if(!isSigned) {
IntRegex = "^[0-9]\\d*(\\.\\d+)?$";
}
return std::regex_match(number, IntRegex);
}
[[nodiscard]] std::string ToHex(const std::vector<unsigned char> &B) {
std::string R;
R.reserve(B.size() * 2);
@@ -599,4 +617,329 @@ namespace OpenWifi::Utils {
return DT.timestamp().epochTime();
}
static std::string FileToString(const std::string &Filename) {
std::ifstream ifs(Filename.c_str(),std::ios_base::in|std::ios_base::binary);
std::ostringstream os;
Poco::StreamCopier::copyStream(ifs,os);
return os.str();
}
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results) {
int ret = 0;
RSA *r = nullptr;
BIGNUM *bne = nullptr;
int nVersion = 0;
unsigned long e = RSA_F4;
X509_REQ *x509_req = nullptr;
X509_NAME *x509_name = nullptr;
EVP_PKEY *pKey = nullptr;
// RSA *tem = nullptr;
// BIO *bio_err = nullptr;
const char *szCountry = Parameters.Country.c_str();
const char *szProvince = Parameters.Province.c_str();
const char *szCity = Parameters.City.c_str();
const char *szOrganization = Parameters.Organization.c_str();
const char *szCommon = Parameters.CommonName.c_str();
Poco::TemporaryFile CsrPath, PubKey, PrivateKey;
std::string Result;
std::ifstream ifs;
std::ostringstream ss;
BIO *bp_public = nullptr,
*bp_private = nullptr,
*bp_csr = nullptr;
// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne,e);
if(ret != 1){
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, Parameters.bits, bne, nullptr);
if(ret != 1){
goto free_all;
}
bp_public = BIO_new_file(PubKey.path().c_str(), "w+");
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if(ret != 1) {
goto free_all;
}
bp_private = BIO_new_file(PrivateKey.path().c_str(), "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
if(ret != 1) {
goto free_all;
}
// 2. set version of x509 req
x509_req = X509_REQ_new();
ret = X509_REQ_set_version(x509_req, nVersion);
if (ret != 1){
goto free_all;
}
// 3. set subject of x509 req
x509_name = X509_REQ_get_subject_name(x509_req);
ret = X509_NAME_add_entry_by_txt(x509_name,"C", MBSTRING_ASC, (const unsigned char*)szCountry, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"ST", MBSTRING_ASC, (const unsigned char*)szProvince, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"L", MBSTRING_ASC, (const unsigned char*)szCity, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"O", MBSTRING_ASC, (const unsigned char*)szOrganization, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"CN", MBSTRING_ASC, (const unsigned char*)szCommon, -1, -1, 0);
if (ret != 1){
goto free_all;
}
// 4. set public key of x509 req
pKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pKey, r);
r = nullptr; // will be free rsa when EVP_PKEY_free(pKey)
ret = X509_REQ_set_pubkey(x509_req, pKey);
if (ret != 1){
goto free_all;
}
// 5. set sign key of x509 req
ret = X509_REQ_sign(x509_req, pKey, EVP_sha1()); // return x509_req->signature->length
if (ret <= 0){
goto free_all;
}
bp_csr = BIO_new_file(CsrPath.path().c_str(),"w");
ret = PEM_write_bio_X509_REQ(bp_csr, x509_req);
// 6. free
free_all:
X509_REQ_free(x509_req);
BIO_free_all(bp_csr);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
EVP_PKEY_free(pKey);
BN_free(bne);
if(ret==1) {
Results.CSR = FileToString(CsrPath.path());
Results.PrivateKey = FileToString(PrivateKey.path());
Results.PublicKey = FileToString(PubKey.path());
}
return ret;
}
bool VerifyECKey(const std::string &key) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << key;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::ECKey>(
new Poco::Crypto::ECKey("", F.path(),""));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool VerifyRSAKey([[
maybe_unused]] const std::string &key) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << key;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::RSAKey>(
new Poco::Crypto::RSAKey("", F.path(),""));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool VerifyPrivateKey(const std::string &key) {
return VerifyECKey(key) || VerifyRSAKey(key);
}
bool ValidX509Certificate([[
maybe_unused]] const std::string &Cert) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << Cert;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::X509Certificate>(
new Poco::Crypto::X509Certificate(F.path()));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool ValidX509Certificate([[
maybe_unused]] const std::vector<std::string> &Certs) {
auto F = [](const std::string &C) -> bool { return ValidX509Certificate(C); };
return std::all_of(Certs.begin(),Certs.end(), F);
}
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase) {
// Define character sets for each category
const std::string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
const std::string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::string digitChars = "0123456789";
const std::string specialChars = "!@#$%^&*()_+[]{}|;:,.<>?";
// Check if parameters are valid
if (minLength < 1 || minLength > maxLength || minLowercase + minUppercase + numDigits + minSpecial > maxLength) {
return "Invalid parameters";
}
// Initialize random seed
std::random_device rd;
std::mt19937 g(rd());
// Initialize the password string
std::string password;
// Generate the required number of each character type
for (int i = 0; i < minLowercase; ++i) {
password += lowercaseChars[g() % lowercaseChars.length()];
}
for (int i = 0; i < minUppercase; ++i) {
password += uppercaseChars[g() % uppercaseChars.length()];
}
for (int i = 0; i < numDigits; ++i) {
password += digitChars[g() % digitChars.length()];
}
for (int i = 0; i < minSpecial; ++i) {
password += specialChars[g() % specialChars.length()];
}
// Calculate how many more characters are needed
int remainingLength = maxLength - (int)password.length();
// Generate random characters to fill the remaining length
for (int i = 0; i < remainingLength; ++i) {
int category = g() % 4; // Randomly select a category
if (category == 0) {
password += lowercaseChars[g() % lowercaseChars.length()];
} else if (category == 1) {
password += uppercaseChars[g() % uppercaseChars.length()];
} else if (category == 2) {
password += digitChars[g() % digitChars.length()];
} else {
password += specialChars[g() % specialChars.length()];
}
}
// Shuffle the password to randomize the character order
std::shuffle(password.begin(), password.end(),g);
return password;
}
// Function to query NAPTR records for a domain and return them in a vector
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain) {
std::vector<NAPTRRecord> naptrRecords;
unsigned char buf[4096];
ns_msg handle;
ns_initparse(buf, NS_PACKETSZ, &handle);
// Query NAPTR records for the given domain
int response = res_query(domain.c_str(), ns_c_in, ns_t_naptr, buf, sizeof(buf));
if (response < 0) {
return naptrRecords;
}
if(ns_initparse(buf, response, &handle) < 0) {
return naptrRecords;
}
// Iterate through the DNS response and extract NAPTR records
int count = ns_msg_count(handle, ns_s_an);
for (int i = 0; i < count; ++i) {
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
char rdata[256];
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
NAPTRRecord record;
std::istringstream os(rdata);
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.order >> record.preference >> record.flags
>> record.service >> record.regexp >> record.replacement;
naptrRecords.push_back(record);
}
}
return naptrRecords;
}
std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
std::vector<SrvRecord> srvRecords;
// Buffer to hold the DNS response
unsigned char buf[4096];
ns_msg handle;
ns_initparse(buf, NS_PACKETSZ, &handle);
// Query NAPTR records for the given domain
int response = res_query(domain.c_str(), ns_c_in, ns_t_srv, buf, sizeof(buf));
if (response < 0) {
std::cerr << "DNS query failed for " << domain << ": " << hstrerror(h_errno) << std::endl;
return srvRecords;
}
if(ns_initparse(buf, response, &handle) < 0) {
return srvRecords;
}
// Iterate through the DNS response and extract NAPTR records
int count = ns_msg_count(handle, ns_s_an);
for (int i = 0; i < count; ++i) {
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
char rdata[256];
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
SrvRecord record;
std::istringstream os(rdata);
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.pref >> record.weight >>
record.port >> record.srvname ;
srvRecords.push_back(record);
}
}
return srvRecords;
}
} // namespace OpenWifi::Utils

View File

@@ -13,6 +13,8 @@
#include <string>
#include <thread>
#include <dirent.h>
#include "Poco/Base64Decoder.h"
#include "Poco/Base64Encoder.h"
#include "Poco/File.h"
@@ -71,6 +73,7 @@ namespace OpenWifi::Utils {
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &Serial);
[[nodiscard]] bool ValidUUID(const std::string &UUID);
[[nodiscard]] bool ValidHostname(const std::string &hostname);
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned);
template <typename... Args> std::string ComputeHash(Args &&...args) {
Poco::SHA2Engine E;
@@ -123,6 +126,20 @@ namespace OpenWifi::Utils {
[[nodiscard]] std::uint64_t ConvertDate(const std::string &d);
[[nodiscard]] inline uint8_t CalculateMacAddressHash(std::uint64_t value) {
uint8_t hash = 0, i=6;
while(i) {
hash ^= (value & 0xFF) + 1;
value >>= 8;
--i;
}
return hash;
}
[[nodiscard]] inline uint8_t CalculateMacAddressHash(const std::string & value) {
return CalculateMacAddressHash(MACToInt(value));
}
template <typename T> std::string int_to_hex(T i) {
std::stringstream stream;
stream << std::setfill('0') << std::setw(12) << std::hex << i;
@@ -181,4 +198,137 @@ namespace OpenWifi::Utils {
return false;
}
static inline std::uint64_t GetValue(FILE *file) {
unsigned long v=0;
char factor[32];
if(fscanf(file, " %lu %31s", &v, factor)==2) {
switch (factor[0]) {
case 'k':
return v * 1000;
case 'M':
return v * 1000000;
case 'G':
return v * 1000000000;
}
}
return v;
}
inline bool getMemory(
std::uint64_t &currRealMem, std::uint64_t &peakRealMem,
std::uint64_t &currVirtMem, std::uint64_t &peakVirtMem) {
// stores each word in status file
char buffer[1024] = "";
currRealMem = peakRealMem = currVirtMem = peakVirtMem = 0;
// linux file contains this-process info
FILE * file = std::fopen("/proc/self/status", "r");
if (file == nullptr) {
return false;
}
// read the entire file, recording mems in kB
while (fscanf(file, " %1023s", buffer) == 1) {
if (strcmp(buffer, "VmRSS:") == 0) {
currRealMem= GetValue(file);
} else if (strcmp(buffer, "VmHWM:") == 0) {
peakRealMem= GetValue(file);
} else if (strcmp(buffer, "VmSize:") == 0) {
currVirtMem= GetValue(file);
} else if (strcmp(buffer, "VmPeak:") == 0) {
peakVirtMem= GetValue(file);
}
}
fclose(file);
return true;
}
inline int get_open_fds() {
DIR *dp = opendir("/proc/self/fd");
struct dirent *de;
int count = -3; // '.', '..', dp
if (dp == nullptr)
return -1;
while ((de = readdir(dp)) != nullptr)
count++;
(void)closedir(dp);
return count;
}
inline std::uint32_t IPtoInt(const std::string &A) {
Poco::Net::IPAddress IP;
std::uint32_t Result=0;
if(Poco::Net::IPAddress::tryParse(A,IP)) {
for(const auto i:IP.toBytes()) {
Result <<= 8;
Result += i;
}
}
return Result;
}
inline bool ValidIP(const std::string &IPstr) {
Poco::Net::IPAddress IP;
return Poco::Net::IPAddress::tryParse(IPstr,IP);
}
struct CSRCreationParameters {
std::string Country, Province, City,
Organization, CommonName;
int bits=2048;
};
struct CSRCreationResults {
std::string CSR, PublicKey, PrivateKey;
};
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results);
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
bool VerifyECKey(const std::string &key);
bool VerifyRSAKey(const std::string &key);
bool VerifyPrivateKey(const std::string &key);
bool ValidX509Certificate(const std::string &Cert);
bool ValidX509Certificate(const std::vector<std::string> &Certs);
struct NAPTRRecord {
std::string name;
std::string ttl;
std::string rclass;
std::string rtype;
uint32_t order=0;
uint32_t preference=0;
std::string flags;
std::string service;
std::string regexp;
std::string replacement;
};
// Function to query NAPTR records for a domain and return them in a vector
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
struct SrvRecord {
std::string name;
std::string ttl;
std::string rclass;
std::string rtype;
uint32_t pref = 0;
uint32_t weight = 0;
uint32_t port = 0;
std::string srvname;
};
std::vector<SrvRecord> getSRVRecords(const std::string& domain);
struct HostNameServerResult{
std::string Hostname;
uint32_t Port;
};
} // namespace OpenWifi::Utils

View File

@@ -21,9 +21,18 @@
#include "Poco/Net/SocketAcceptor.h"
#include <algorithm>
/*
#define DBGLINE \
{ std::cout << __LINE__ << std::endl; }
2023-09-25 14:57:48.963 RADSEC: radsec.openro.am@3.33.129.120:2084: [Error][thr:7] SSL connection unexpectedly closed
2023-09-25 14:57:48.964 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:7] Disconnecting.
2023-09-25 14:57:50.965 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:40] Attempting to connect
2023-09-25 14:57:51.675 RTTY-SVR: [Error][thr:6] Frame readable shutdown.
2023-09-25 14:57:51.675 RTTY-SVR: [Debug][thr:6] Closing connection onClientSocketReadable:646
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:40] Connected. CN=radsec.openro.am
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Error][thr:7] SSL connection unexpectedly closed
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:7] Disconnecting.
*/
namespace OpenWifi {
@@ -440,11 +449,9 @@ namespace OpenWifi {
std::size_t agg_buf_pos=0;
try {
// std::cout << "Available: " << buffer.available() << " ";
Poco::Timespan TS(5,0);
received_bytes = hint->second->socket.receiveBytes(buffer);
if(received_bytes==0) {
// std::cout << hint->second->socket.lastError() << std::endl;
poco_warning(Logger(), "Device Closing connection - 0 bytes received.");
EndConnection( pNf->socket(), __func__, __LINE__ );
return;
@@ -485,9 +492,6 @@ namespace OpenWifi {
return;
}
// std::cout << line++ << " Available: " << buffer.available() << " Cmd: " << (int) LastCommand << " Received: " << received_bytes
// << " MsgLen: " << msg_len << " Data in buffer: " << buffer.used() << std::endl;
buffer.drain(RTTY_HDR_SIZE);
switch (LastCommand) {
@@ -537,8 +541,6 @@ namespace OpenWifi {
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
}
// std::cout << "Empty: " << buffer.isEmpty() << std::endl;
if (!good) {
EndConnection(pNf->socket(), __func__, __LINE__);
}
@@ -583,7 +585,7 @@ namespace OpenWifi {
}
int flags;
unsigned char FrameBuffer[1024];
unsigned char FrameBuffer[64000];
auto ReceivedBytes = Connection->WSSocket_->receiveFrame(FrameBuffer, sizeof(FrameBuffer), flags);
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
@@ -1040,7 +1042,6 @@ namespace OpenWifi {
// buffer.drain(msg_len);
return true;
} catch (const Poco::Exception &E) {
std::cout << "Failed to send WS stuff" << std::endl;
Logger().log(E);
} catch (const std::exception &E) {
LogStdException(E, "Cannot send data to UI Client");

38
src/sdks/sdk_fms.h Normal file
View File

@@ -0,0 +1,38 @@
//
// Created by stephane bourque on 2023-07-12.
//
#pragma once
#include "RESTObjects/RESTAPI_FMSObjects.h"
#include "framework/MicroServiceNames.h"
#include "framework/OpenAPIRequests.h"
#include "framework/RESTAPI_utils.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Logger.h"
#include "fmt/format.h"
namespace OpenWifi::SDK::FMS {
inline bool GetFirmwareAge( const std::string &deviceType, const std::string &revision, FMSObjects::FirmwareAgeDetails Age, Poco::Logger &Logger) {
OpenAPIRequestGet GetFirmwareAgeAPI(
uSERVICE_FIRMWARE, "/api/v1/firmwareAge" ,
{
{ RESTAPI::Protocol::DEVICETYPE, deviceType },
{ RESTAPI::Protocol::REVISION, revision }
}, 30000);
auto CallResponse = Poco::makeShared<Poco::JSON::Object>();
if (!GetFirmwareAgeAPI.Do(CallResponse, "")) {
Logger.error(fmt::format("{}: Cannot find revision.", revision));
return false;
}
if(Age.from_json(CallResponse)) {
return true;
}
return false;
}
} // namespace OpenWifi::SDK::Prov

View File

@@ -0,0 +1,248 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by stephane bourque on 2023-07-11.
// Arilia Wireless Inc.
//
#include "CentralConfig.h"
#include "StorageService.h"
#include "fmt/format.h"
#include "framework/RESTAPI_utils.h"
namespace OpenWifi {
const static std::string DB_DefFirmware_SelectFields_ForCreation{
"deviceType VARCHAR(128) PRIMARY KEY, "
"uri TEXT, "
"revision TEXT, "
"Description TEXT, "
"Created BIGINT , "
"imageCreationDate BIGINT , "
"LastModified BIGINT)" };
const static std::string DB_DefFirmware_SelectFields{
"deviceType, "
"uri, "
"revision, "
"Description, "
"Created, "
"imageCreationDate, "
"LastModified "};
const static std::string DB_DefFirmware_InsertValues{"?,?,?,?,?,?,?"};
typedef Poco::Tuple<std::string,
std::string,
std::string,
std::string,
uint64_t,
uint64_t,
uint64_t>
DefFirmwareRecordTuple;
typedef std::vector<DefFirmwareRecordTuple> DefFirmwareRecordList;
void Convert(const DefFirmwareRecordTuple &R, GWObjects::DefaultFirmware &T) {
T.deviceType = R.get<0>();
T.uri = R.get<1>();
T.revision = R.get<2>();
T.Description = R.get<3>();
T.Created = R.get<4>();
T.imageCreationDate = R.get<5>();
T.LastModified = R.get<6>();
}
void Convert(const GWObjects::DefaultFirmware &R, DefFirmwareRecordTuple &T) {
T.set<0>(R.deviceType);
T.set<1>(R.uri);
T.set<2>(R.revision);
T.set<3>(R.Description);
T.set<4>(R.Created);
T.set<5>(R.imageCreationDate);
T.set<6>(R.LastModified);
}
bool Storage::CreateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware) {
try {
std::string TmpName;
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
Poco::toLowerInPlace(DefFirmware.deviceType);
std::string St{"SELECT DeviceType FROM DefaultFirmwares WHERE deviceType=?"};
Select << ConvertParams(St),
Poco::Data::Keywords::into(TmpName),
Poco::Data::Keywords::use(DefFirmware.deviceType);
Select.execute();
if (!TmpName.empty())
return false;
Poco::Data::Statement Insert(Sess);
std::string St2{"INSERT INTO DefaultFirmwares ( " + DB_DefFirmware_SelectFields +
" ) "
"VALUES(" +
DB_DefFirmware_InsertValues + ")"};
DefFirmwareRecordTuple R;
Convert(DefFirmware, R);
Insert << ConvertParams(St2),
Poco::Data::Keywords::use(R);
Insert.execute();
return true;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
bool Storage::DeleteDefaultFirmware(std::string &deviceType) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
Poco::toLowerInPlace(deviceType);
std::string St{"DELETE FROM DefaultFirmwares WHERE deviceType=?"};
Delete << ConvertParams(St), Poco::Data::Keywords::use(deviceType);
Delete.execute();
return true;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
bool Storage::UpdateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware) {
try {
Poco::Data::Session Sess = Pool_->get();
uint64_t Now = time(nullptr);
Poco::Data::Statement Update(Sess);
DefFirmware.LastModified = Now;
Poco::toLowerInPlace(DefFirmware.deviceType);
std::string St{"UPDATE DefaultFirmwares SET deviceType=?, uri=?, revision=?, "
"Description=?, Created=? , imageCreationDate=?, LastModified=? WHERE deviceType=?"};
DefFirmwareRecordTuple R;
Convert(DefFirmware, R);
Update << ConvertParams(St),
Poco::Data::Keywords::use(R),
Poco::Data::Keywords::use(DefFirmware.deviceType);
Update.execute();
return true;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
bool Storage::GetDefaultFirmware(std::string &deviceType,
GWObjects::DefaultFirmware &DefFirmware) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
Poco::toLowerInPlace(deviceType);
std::string St{"SELECT " + DB_DefFirmware_SelectFields +
" FROM DefaultFirmwares WHERE deviceType=?"};
DefFirmwareRecordTuple R;
Select << ConvertParams(St),
Poco::Data::Keywords::into(R),
Poco::Data::Keywords::use(deviceType);
Select.execute();
if (Select.rowsExtracted() == 1) {
Convert(R, DefFirmware);
return true;
}
return false;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
bool Storage::DefaultFirmwareAlreadyExists(std::string &deviceType) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
Poco::toLowerInPlace(deviceType);
std::string St{"SELECT " + DB_DefFirmware_SelectFields +
" FROM DefaultFirmwares WHERE deviceType=?"};
DefFirmwareRecordTuple R;
Select << ConvertParams(St), Poco::Data::Keywords::into(R),
Poco::Data::Keywords::use(deviceType);
Select.execute();
return Select.rowsExtracted() == 1;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
bool
Storage::GetDefaultFirmwares(uint64_t From, uint64_t HowMany,
std::vector<GWObjects::DefaultFirmware> &Firmwares) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
DefFirmwareRecordList Records;
Select << "SELECT " + DB_DefFirmware_SelectFields +
" FROM DefaultFirmwares ORDER BY deviceType ASC " + ComputeRange(From, HowMany),
Poco::Data::Keywords::into(Records);
Select.execute();
Firmwares.clear();
for (const auto &i : Records) {
GWObjects::DefaultFirmware R;
Convert(i, R);
Firmwares.push_back(R);
}
return true;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return false;
}
uint64_t Storage::GetDefaultFirmwaresCount() {
uint64_t Count = 0;
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
Select << "SELECT Count(*) from DefaultFirmwares", Poco::Data::Keywords::into(Count);
Select.execute();
return Count;
} catch (const Poco::Exception &E) {
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
E.displayText()));
}
return Count;
}
} // namespace OpenWifi

View File

@@ -53,7 +53,9 @@ namespace OpenWifi {
"restrictionDetails, "
"pendingUUID, "
"simulated,"
"lastRecordedContact"
"lastRecordedContact,"
"certificateExpiryDate,"
"connectReason "
};
const static std::string DB_DeviceUpdateFields{"SerialNumber=?,"
@@ -84,16 +86,20 @@ namespace OpenWifi {
"restrictionDetails=?, "
"pendingUUID=?, "
"simulated=?,"
"lastRecordedContact=? "};
"lastRecordedContact=?, "
"certificateExpiryDate=?,"
"connectReason=? "
};
const static std::string DB_DeviceInsertValues{
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
typedef Poco::Tuple<std::string, std::string, std::string, std::string, std::string,
std::string, std::string, std::string, std::string, std::string,
std::string, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, std::string,
std::string, std::string, std::string, uint64_t, std::string, bool,
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t>
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t,
std::uint64_t, std::string>
DeviceRecordTuple;
typedef std::vector<DeviceRecordTuple> DeviceRecordList;
@@ -128,6 +134,8 @@ namespace OpenWifi {
D.pendingUUID = R.get<26>();
D.simulated = R.get<27>();
D.lastRecordedContact = R.get<28>();
D.certificateExpiryDate = R.get<29>();
D.connectReason = R.get<30>();
}
void ConvertDeviceRecord(const GWObjects::Device &D, DeviceRecordTuple &R) {
@@ -160,6 +168,8 @@ namespace OpenWifi {
R.set<26>(D.pendingUUID);
R.set<27>(D.simulated);
R.set<28>(D.lastRecordedContact);
R.set<29>(D.certificateExpiryDate);
R.set<30>(D.connectReason);
}
bool Storage::GetDeviceCount(uint64_t &Count) {
@@ -382,11 +392,11 @@ namespace OpenWifi {
std::string St{"SELECT SerialNumber FROM Devices WHERE SerialNumber=?"};
Select << ConvertParams(St), Poco::Data::Keywords::into(SerialNumber),
Poco::Data::Keywords::use(DeviceDetails.SerialNumber);
Select.execute();
// Select << ConvertParams(St), Poco::Data::Keywords::into(SerialNumber),
// Poco::Data::Keywords::use(DeviceDetails.SerialNumber);
// Select.execute();
if (Select.rowsExtracted() == 0) {
// if (Select.rowsExtracted() == 0) {
Config::Config Cfg(DeviceDetails.Configuration);
uint64_t Now = Utils::Now();
@@ -400,7 +410,7 @@ namespace OpenWifi {
Poco::Data::Statement Insert(Sess);
std::string St2{"INSERT INTO Devices ( " + DB_DeviceSelectFields + " ) " +
DB_DeviceInsertValues};
DB_DeviceInsertValues + " ON CONFLICT (SerialNumber) DO NOTHING"};
SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID);
DeviceRecordTuple R;
@@ -414,11 +424,11 @@ namespace OpenWifi {
poco_warning(Logger(), "Cannot create device: invalid configuration.");
return false;
}
} else {
poco_warning(Logger(), fmt::format("Device {} already exists.", SerialNumber));
return false;
}
// } else {
// poco_warning(Logger(), fmt::format("Device {} already exists.", SerialNumber));
// return false;
// }
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
@@ -447,6 +457,36 @@ namespace OpenWifi {
return FoundCountry;
}
bool Storage::DeleteSimulatedDevice([[maybe_unused]] const std::string &SerialNumber) {
std::vector<std::string> Statements =
{
"delete from commandlist using devices where commandlist.serialnumber=devices.serialnumber and devices.simulated=true;",
"delete from healthchecks using devices where healthchecks.serialnumber=devices.serialnumber and devices.simulated=true;",
"delete from statistics using devices where statistics.serialnumber=devices.serialnumber and devices.simulated=true;",
"delete from devicelogs using devices where devicelogs.serialnumber=devices.serialnumber and devices.simulated=true;",
"delete from capabilities using devices where capabilities.serialnumber=devices.serialnumber and devices.simulated=true;",
"delete from devices where devices.simulated=true;"
};
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Command(Sess);
for (const auto &i : Statements) {
try {
Command << i, Poco::Data::Keywords::now;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
Command.reset(Sess);
}
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return true;
}
#define __DBGLOG__ std::cout << __LINE__ << std::endl;
bool Storage::CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
@@ -590,9 +630,7 @@ namespace OpenWifi {
Poco::JSON::Object Message;
Message.set("command", "device_deleted");
Message.set("timestamp", Utils::Now());
std::ostringstream StrPayload;
Message.stringify(StrPayload);
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, std::make_shared<std::string>(StrPayload.str()));
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, Message);
}
return true;

View File

@@ -21,6 +21,7 @@ namespace OpenWifi {
Create_CommandList();
Create_BlackList();
Create_FileUploads();
Create_DefaultFirmwares();
return 0;
}
@@ -39,12 +40,15 @@ namespace OpenWifi {
Sess << "CREATE INDEX IF NOT EXISTS StatsSerial ON Statistics (SerialNumber ASC, "
"Recorded ASC)",
Poco::Data::Keywords::now;
Sess << "CREATE INDEX IF NOT EXISTS StatsSerial0 ON Statistics (SerialNumber ASC)",
Poco::Data::Keywords::now;
} else if (dbType_ == mysql) {
Sess << "CREATE TABLE IF NOT EXISTS Statistics ("
"SerialNumber VARCHAR(30), "
"UUID INTEGER, "
"Data TEXT, "
"Recorded BIGINT, "
"INDEX StatSerial0 (SerialNumber)), ",
"INDEX StatSerial (SerialNumber ASC, Recorded ASC))",
Poco::Data::Keywords::now;
}
@@ -89,7 +93,9 @@ namespace OpenWifi {
"restrictionDetails TEXT, "
"pendingUUID BIGINT, "
"simulated BOOLEAN,"
"lastRecordedContact BIGINT"
"lastRecordedContact BIGINT,"
"certificateExpiryDate BIGINT,"
"connectReason TEXT"
",INDEX DeviceOwner (Owner ASC),"
"INDEX LocationIndex (Location ASC))",
Poco::Data::Keywords::now;
@@ -123,7 +129,9 @@ namespace OpenWifi {
"restrictionDetails TEXT,"
"pendingUUID BIGINT, "
"simulated BOOLEAN, "
"lastRecordedContact BIGINT"
"lastRecordedContact BIGINT,"
"certificateExpiryDate BIGINT,"
"connectReason TEXT"
")",
Poco::Data::Keywords::now;
Sess << "CREATE INDEX IF NOT EXISTS DeviceOwner ON Devices (Owner ASC)",
@@ -144,7 +152,9 @@ namespace OpenWifi {
"alter table devices add column restrictionDetails TEXT",
"alter table devices add column pendingUUID bigint",
"alter table devices add column lastRecordedContact bigint",
"alter table devices add column simulated boolean"
"alter table devices add column simulated boolean",
"alter table devices add column certificateExpiryDate bigint",
"alter table devices add column connectReason TEXT"
};
for (const auto &i : Script) {
@@ -275,6 +285,28 @@ namespace OpenWifi {
return -1;
}
int Storage::Create_DefaultFirmwares() {
try {
Poco::Data::Session Sess = Pool_->get();
if (dbType_ == pgsql || dbType_ == sqlite || dbType_ == mysql) {
Sess << "CREATE TABLE IF NOT EXISTS DefaultFirmwares ("
"deviceType VARCHAR(128) PRIMARY KEY, "
"uri TEXT, "
"revision TEXT, "
"Description TEXT, "
"Created BIGINT , "
"imageCreationDate BIGINT , "
"LastModified BIGINT)",
Poco::Data::Keywords::now;
}
return 0;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return -1;
}
// mysql = float
// sqlite, postgresql = real

View File

@@ -83,82 +83,77 @@ setgateway() {
-H "Authorization: Bearer ${token}" > ${result_file}
rawurl="$(cat < ${result_file} | jq -r '.endpoints[] | select( .type == "owgw" ) | .uri')"
if [[ ! -z "${rawurl}" ]]; then
proto="$(echo "$rawurl" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
# shellcheck disable=SC2116
url="$(echo "${rawurl/$proto/}")"
user="$(echo $url | grep @ | cut -d@ -f1)"
hostport="$(echo ${url/$user@/} | cut -d/ -f1)"
host="$(echo $hostport | sed -e 's,:.*,,g')"
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
path="$(echo $url | grep / | cut -d/ -f2-)"
export OWGW=${url}
echo "Using ${OWGW}..."
else
echo "OWGW endpoint is not found:"
jq < ${result_file}
exit 1
fi
else
export OWGW=${OWGW_OVERRIDE}
proto="$(echo "$rawurl" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
url="$(echo "${rawurl/$proto/}")"
user="$(echo $url | grep @ | cut -d@ -f1)"
export OWGW=${url}
echo "Using ${OWGW}..."
else
echo "OWGW endpoint is not found:"
jq < ${result_file}
exit 1
fi
else
export OWGW=${OWGW_OVERRIDE}
fi
}
logout() {
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${token}"
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${token}"
rm -rf token.json
}
getdevice() {
curl ${FLAGS} -X GET --url "https://${OWGW}/api/v1/device/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
curl ${FLAGS} -X GET --url "https://${OWGW}/api/v1/device/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
getcommand() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/command/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletecommand() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/command/$1" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}"
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}"
}
listcommands() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/commands?serialNumber=$1&limit=300" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
newestcommands() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/commands?serialNumber=$1&newest=true&limit=50" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletecommands() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/commands?serialNumber=$1" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}"
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}"
}
getcapabilities() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/device/$1/capabilities" \
-H "accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletecapabilities() {
@@ -169,42 +164,42 @@ deletecapabilities() {
listdevices() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletesimdevices() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedOnly=true&macPattern=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletebulkdevices() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?macPattern=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
listdevicesk() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-API-KEY: $1" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-API-KEY: $1" > ${result_file}
jq < ${result_file}
}
ldevs() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?offset=$1&limit=$2" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletedevice() {
@@ -299,6 +294,14 @@ systeminfo() {
jq < ${result_file}
}
systemresources() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/system?command=resources" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
reloadsubsystem() {
payload="{ \"command\" : \"reload\", \"subsystems\" : [ \"$1\" ] }"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/system" \
@@ -652,7 +655,7 @@ validateconfig() {
wstest() {
echo "Token:${token}"
wscat \
-c wss://${OWGW}/api/v1/ws
-c wss://"${OWGW}"/api/v1/ws
}
telemetry() {
@@ -704,7 +707,7 @@ telemetry_to_kafka() {
}
runscript() {
scriptcontent=$(base64 -i $3)
scriptcontent=$(base64 -i "$3")
payload="$(printf '{ "serialNumber": "%s", "type": "%s" , "timeout": 30, "script" : "%s" , "deferred" : false, "when" : 0 }' "$1" "$2" "$scriptcontent" )"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/script" \
-H "Content-Type: application/json" \
@@ -726,61 +729,61 @@ runscriptname() {
deviceping() {
payload="$(printf '{ "serialNumber": "%s" }' "$1" )"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/ping" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/ping" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
caplist() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/capabilities" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
iptocountry() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/iptocountry?iplist=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
setradiusconfig() {
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusProxyConfig" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "@${1}" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "@${1}" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
getradiusconfig() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusProxyConfig" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deleteradiusconfig() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/radiusProxyConfig" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
connectionstatistics() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?connectionStatistics=true" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
testtoken() {
@@ -828,76 +831,129 @@ stats7count() {
listscripts() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/scripts" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
getscript() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/script/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
regulatory() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/regulatory?countries=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
regulatory_reload() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/regulatory?reload=true" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiussessions() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiussearch() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?userName=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiussearchmac() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?mac=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiusaps() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?serialNumberOnly=true" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiuscoadm() {
payload="$(printf '{ "accountingSessionId": "%s", "accountingMultiSessionId": "%s" , "callingStationId": "%s" }' "$2" "$3" "$4" )"
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusSessions/$1?operation=coadm" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
listdefaultfirmwares() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/default_firmwares" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
getdefaultfirmware() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/default_firmware/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
transferdevice() {
payload="$(printf '{ "serialNumber": "%s", "server": "%s" , "port": %s}' "$1" "$2" "$3")"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/transfer" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
certupdate() {
payload="$(printf '{ "serialNumber": "%s", "encodedCertificate": "%s"}' "$1" "$2")"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/certupdate" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
rrm_kick() {
payload="$(printf '{ "actions" : [{ "action": "kick", "addr": "%s", "reason": %s, "ban_time": %s}] }' "$2" "$3" "$4")"
echo "$payload"
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/rrm" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
deletesimulateddevices() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedDevices=true" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}"
}
check_response() {
@@ -1150,6 +1206,7 @@ case "$1" in
"getsubsystemnames") login; getsubsystemnames; logout ;;
"reloadsubsystem") login; reloadsubsystem "$2"; logout ;;
"systeminfo") login; systeminfo ; logout;;
"systemresources") login; systemresources ; logout;;
"ouilookup") login; ouilookup "$2"; logout;;
"telemetry") login; telemetry "$2"; logout;;
"telemetry_to_kafka") login; telemetry_to_kafka "$2" "$3"; logout;;
@@ -1183,6 +1240,12 @@ case "$1" in
"radiussearchmac") login; radiussearchmac "$2"; logout;;
"deletesimdevices") login; deletesimdevices "$2"; logout;;
"deletebulkdevices") login; deletebulkdevices "$2"; logout;;
"listdefaultfirmwares") login; listdefaultfirmwares; logout;;
"getdefaultfirmware") login; getdefaultfirmware "$2"; logout;;
"transferdevice") login; transferdevice "$2" "$3" "$4"; logout;;
"certupdate") login; certupdate "$2" "$3"; logout;;
"rrm_kick") login; rrm_kick "$2" "$3" "$4" "$5"; logout;;
"deletesimulateddevices") login; deletesimulateddevices ; logout;;
"testtoken") testtoken;;
*) help ;;
esac