376 lines
11 KiB
C
376 lines
11 KiB
C
|
/*
|
||
|
* ni-add-ip-dialog.c
|
||
|
* This file is part of Network Inador
|
||
|
*
|
||
|
* Copyright (C) 2021 - Gatuno
|
||
|
*
|
||
|
* Network Inador is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Network Inador is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Network Inador; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||
|
* Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#include <gtk/gtk.h>
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <arpa/inet.h>
|
||
|
|
||
|
#include "ni-add-ip-dialog.h"
|
||
|
#include "ni-ip.h"
|
||
|
|
||
|
struct _NIAddIPDialogPrivate {
|
||
|
int family;
|
||
|
|
||
|
GtkWidget *entry;
|
||
|
|
||
|
GtkWidget *button_add;
|
||
|
|
||
|
GtkWidget *check_p2p, *entry_p2p;
|
||
|
GtkWidget *check_noprefix;
|
||
|
gboolean valid_main_ip, valid_p2p_ip;
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
PROP_IP_FAMILY = 1,
|
||
|
|
||
|
N_PROPERTIES
|
||
|
};
|
||
|
|
||
|
G_DEFINE_TYPE_WITH_PRIVATE (NIAddIPDialog, ni_add_ip_dialog, GTK_TYPE_DIALOG)
|
||
|
|
||
|
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
||
|
|
||
|
static void split_ip_mask (const char *texto, gchar *ip, int ip_size, gchar *mask, int mask_size) {
|
||
|
gchar *dup;
|
||
|
int g, has_slash = -1;
|
||
|
|
||
|
mask[0] = 0;
|
||
|
dup = g_strdup (texto);
|
||
|
|
||
|
for (g = 0; g < strlen (texto); g++) {
|
||
|
if (texto[g] == '/' && texto[g + 1] != 0) {
|
||
|
has_slash = g;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (has_slash >= 0) {
|
||
|
strncpy (mask, &texto[has_slash + 1], mask_size);
|
||
|
strncpy (ip, texto, ip_size);
|
||
|
ip[has_slash] = 0;
|
||
|
} else {
|
||
|
strncpy (ip, texto, ip_size);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gboolean ip_valid_ipv4 (const char *ip) {
|
||
|
struct in_addr addr;
|
||
|
|
||
|
if (inet_pton (AF_INET, ip, &addr) == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean ip_valid_ipv6 (const char *ip) {
|
||
|
struct in6_addr addr;
|
||
|
|
||
|
if (inet_pton (AF_INET6, ip, &addr) == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_update_response (NIAddIPDialog *dialog) {
|
||
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) && dialog->priv->valid_p2p_ip == FALSE) {
|
||
|
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (dialog->priv->valid_main_ip == FALSE) {
|
||
|
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_validate_main_ip (GtkEditable *editable, gpointer data) {
|
||
|
NIAddIPDialog *dialog = NI_ADD_IP_DIALOG (data);
|
||
|
struct_addr addr;
|
||
|
int prefix;
|
||
|
|
||
|
dialog->priv->valid_main_ip = ni_add_ip_dialog_get_address (dialog, &addr, &prefix);
|
||
|
ni_add_ip_dialog_update_response (dialog);
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_validate_p2p_ip (GtkEditable *editable, gpointer data) {
|
||
|
NIAddIPDialog *dialog = NI_ADD_IP_DIALOG (data);
|
||
|
const gchar *texto;
|
||
|
int prefix;
|
||
|
|
||
|
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p));
|
||
|
|
||
|
dialog->priv->valid_p2p_ip = FALSE;
|
||
|
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
|
||
|
dialog->priv->valid_p2p_ip = ip_valid_ipv4 (texto);
|
||
|
if (dialog->priv->valid_p2p_ip) {
|
||
|
ni_add_ip_dialog_update_response (dialog);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
|
||
|
dialog->priv->valid_p2p_ip = ip_valid_ipv6 (texto);
|
||
|
}
|
||
|
|
||
|
ni_add_ip_dialog_update_response (dialog);
|
||
|
}
|
||
|
|
||
|
void ni_add_ip_dialog_toggle_p2p_cb (GtkWidget *widget, gpointer data) {
|
||
|
NIAddIPDialog *dialog = NI_ADD_IP_DIALOG (data);
|
||
|
|
||
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
|
||
|
gtk_widget_set_sensitive (dialog->priv->entry_p2p, TRUE);
|
||
|
} else {
|
||
|
gtk_widget_set_sensitive (dialog->priv->entry_p2p, FALSE);
|
||
|
}
|
||
|
ni_add_ip_dialog_update_response (dialog);
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
|
||
|
NIAddIPDialog *dialog = NI_ADD_IP_DIALOG (object);
|
||
|
g_return_if_fail (NI_IS_ADD_IP_DIALOG (object));
|
||
|
|
||
|
switch (prop_id) {
|
||
|
case PROP_IP_FAMILY:
|
||
|
dialog->priv->family = g_value_get_uint (value);
|
||
|
if (dialog->priv->family == AF_UNSPEC) {
|
||
|
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "192.0.2.1/24 or 2001:db8::1/64");
|
||
|
} else if (dialog->priv->family == AF_INET) {
|
||
|
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "192.0.2.1/24");
|
||
|
} else if (dialog->priv->family == AF_INET6) {
|
||
|
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "2001:db8::1/64");
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
|
||
|
NIAddIPDialog *dialog = NI_ADD_IP_DIALOG (object);
|
||
|
g_return_if_fail (NI_IS_ADD_IP_DIALOG (object));
|
||
|
|
||
|
switch (prop_id) {
|
||
|
case PROP_IP_FAMILY:
|
||
|
g_value_set_uint (value, dialog->priv->family);
|
||
|
break;
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_class_init (NIAddIPDialogClass *klass) {
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
|
||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||
|
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
|
||
|
|
||
|
object_class->set_property = ni_add_ip_dialog_set_property;
|
||
|
object_class->get_property = ni_add_ip_dialog_get_property;
|
||
|
|
||
|
obj_properties[PROP_IP_FAMILY] = g_param_spec_uint (
|
||
|
"family",
|
||
|
"Network family",
|
||
|
"Network family to allow",
|
||
|
0, 10, AF_UNSPEC,
|
||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||
|
|
||
|
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
|
||
|
}
|
||
|
|
||
|
static void ni_add_ip_dialog_init (NIAddIPDialog *dialog) {
|
||
|
NIAddIPDialogPrivate *priv = ni_add_ip_dialog_get_instance_private (dialog);
|
||
|
GtkWidget *image;
|
||
|
GtkWidget *vbox, *expander;
|
||
|
GtkWidget *container, *label, *hbox;
|
||
|
|
||
|
dialog->priv = priv;
|
||
|
|
||
|
priv->family = AF_UNSPEC;
|
||
|
|
||
|
gtk_window_set_title (GTK_WINDOW (dialog), "Add new IP");
|
||
|
|
||
|
gtk_dialog_add_button (GTK_DIALOG (dialog), "Cancelar", GTK_RESPONSE_CANCEL);
|
||
|
|
||
|
priv->button_add = gtk_dialog_add_button (GTK_DIALOG (dialog), "Agregar", GTK_RESPONSE_OK);
|
||
|
image = gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
||
|
gtk_button_set_image (GTK_BUTTON (priv->button_add), image);
|
||
|
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
|
||
|
|
||
|
container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||
|
gtk_box_pack_start (GTK_BOX (container), vbox, TRUE, TRUE, 0);
|
||
|
|
||
|
label = gtk_label_new ("Ingrese los detalles sobre la dirección IP:");
|
||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5);
|
||
|
|
||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||
|
|
||
|
label = gtk_label_new ("IP:");
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
||
|
|
||
|
priv->entry = gtk_entry_new ();
|
||
|
gtk_entry_set_placeholder_text (GTK_ENTRY (priv->entry), "192.0.2.1/24 or 2001:db8::1/64");
|
||
|
g_signal_connect (priv->entry, "changed", G_CALLBACK (ni_add_ip_dialog_validate_main_ip), dialog);
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), priv->entry, TRUE, TRUE, 0);
|
||
|
|
||
|
expander = gtk_expander_new_with_mnemonic ("_Opciones avanzadas");
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
|
||
|
|
||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
|
||
|
gtk_container_add (GTK_CONTAINER (expander), vbox);
|
||
|
|
||
|
/* La posible dirección peer-to-peer */
|
||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3);
|
||
|
|
||
|
priv->check_p2p = gtk_check_button_new_with_label ("Point-to-point address:");
|
||
|
g_signal_connect (priv->check_p2p, "toggled", G_CALLBACK (ni_add_ip_dialog_toggle_p2p_cb), dialog);
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), priv->check_p2p, FALSE, FALSE, 0);
|
||
|
|
||
|
priv->entry_p2p = gtk_entry_new ();
|
||
|
g_signal_connect (priv->entry_p2p, "changed", G_CALLBACK (ni_add_ip_dialog_validate_p2p_ip), dialog);
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), priv->entry_p2p, TRUE, TRUE, 0);
|
||
|
gtk_widget_set_sensitive (priv->entry_p2p, FALSE);
|
||
|
|
||
|
priv->check_noprefix = gtk_check_button_new_with_label ("No prefix route");
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), priv->check_noprefix, FALSE, FALSE, 3);
|
||
|
|
||
|
dialog->priv->valid_main_ip = FALSE;
|
||
|
dialog->priv->valid_p2p_ip = FALSE;
|
||
|
|
||
|
gtk_widget_show_all (container);
|
||
|
}
|
||
|
|
||
|
gboolean ni_add_ip_dialog_get_address (NIAddIPDialog *dialog, struct_addr *addr, int *prefix) {
|
||
|
const gchar *texto;
|
||
|
gchar *rest, ip[128], mask[32];
|
||
|
int lprefix;
|
||
|
gboolean valid;
|
||
|
|
||
|
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry));
|
||
|
|
||
|
split_ip_mask (texto, ip, sizeof (ip), mask, sizeof (mask));
|
||
|
|
||
|
if (mask[0] != 0) {
|
||
|
lprefix = g_ascii_strtoll (mask, &rest, 10);
|
||
|
|
||
|
if (rest[0] != 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
|
||
|
valid = ip_valid_ipv4 (ip);
|
||
|
if (valid == FALSE ||
|
||
|
(mask[0] != 0 && (lprefix <= 0 || lprefix > 32))) {
|
||
|
if (dialog->priv->family == AF_INET) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
} else {
|
||
|
*prefix = 32;
|
||
|
if (mask[0] != 0) {
|
||
|
*prefix = lprefix;
|
||
|
}
|
||
|
inet_pton (AF_INET, ip, addr);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
|
||
|
valid = ip_valid_ipv6 (ip);
|
||
|
if (valid == FALSE || (mask[0] != 0 && (lprefix <= 0 || lprefix > 128))) {
|
||
|
dialog->priv->valid_main_ip = FALSE;
|
||
|
return FALSE;
|
||
|
} else {
|
||
|
*prefix = 128;
|
||
|
if (mask[0] != 0) {
|
||
|
*prefix = lprefix;
|
||
|
}
|
||
|
inet_pton (AF_INET6, ip, addr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
gboolean ni_add_ip_dialog_has_p2p_address (NIAddIPDialog *dialog) {
|
||
|
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p));
|
||
|
}
|
||
|
|
||
|
gboolean ni_add_ip_dialog_get_p2p_address (NIAddIPDialog *dialog, struct_addr *addr) {
|
||
|
gboolean valid;
|
||
|
const gchar *texto;
|
||
|
|
||
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) == FALSE) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p));
|
||
|
|
||
|
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
|
||
|
valid = ip_valid_ipv4 (texto);
|
||
|
|
||
|
if (valid) {
|
||
|
inet_pton (AF_INET, texto, addr);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
|
||
|
valid = ip_valid_ipv6 (texto);
|
||
|
|
||
|
if (valid) {
|
||
|
inet_pton (AF_INET6, texto, addr);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
gboolean ni_add_ip_dialog_get_noprefix (NIAddIPDialog *dialog) {
|
||
|
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_noprefix));
|
||
|
}
|
||
|
|
||
|
GtkWidget* ni_add_ip_dialog_new (int family) {
|
||
|
NIAddIPDialog *dialog;
|
||
|
|
||
|
dialog = g_object_new (NI_TYPE_ADD_IP_DIALOG, "family", family, NULL);
|
||
|
|
||
|
return GTK_WIDGET (dialog);
|
||
|
}
|
||
|
|