| 43 | | |
|---|
| 44 | | /** |
|---|
| 45 | | * Run the up/down script |
|---|
| 46 | | */ |
|---|
| 47 | | static void updown(ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) |
|---|
| 48 | | { |
|---|
| 49 | | traffic_selector_t *my_ts, *other_ts; |
|---|
| 50 | | enumerator_t *enumerator; |
|---|
| 51 | | child_cfg_t *config; |
|---|
| 52 | | host_t *vip, *me, *other; |
|---|
| 53 | | char *script; |
|---|
| 54 | | |
|---|
| 55 | | config = child_sa->get_config(child_sa); |
|---|
| 56 | | vip = ike_sa->get_virtual_ip(ike_sa, TRUE); |
|---|
| 57 | | script = config->get_updown(config); |
|---|
| 58 | | me = ike_sa->get_my_host(ike_sa); |
|---|
| 59 | | other = ike_sa->get_other_host(ike_sa); |
|---|
| 60 | | |
|---|
| 61 | | if (script == NULL) |
|---|
| 62 | | { |
|---|
| 63 | | return; |
|---|
| 64 | | } |
|---|
| 65 | | |
|---|
| 66 | | enumerator = child_sa->create_policy_enumerator(child_sa); |
|---|
| 67 | | while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) |
|---|
| 68 | | { |
|---|
| 69 | | char command[1024]; |
|---|
| 70 | | char *my_client, *other_client, *my_client_mask, *other_client_mask; |
|---|
| 71 | | char *pos, *virtual_ip, *iface; |
|---|
| 72 | | FILE *shell; |
|---|
| 73 | | |
|---|
| 74 | | /* get subnet/bits from string */ |
|---|
| 75 | | if (asprintf(&my_client, "%R", my_ts) < 0) |
|---|
| 76 | | { |
|---|
| 77 | | my_client = NULL; |
|---|
| 78 | | } |
|---|
| 79 | | pos = strchr(my_client, '/'); |
|---|
| 80 | | *pos = '\0'; |
|---|
| 81 | | my_client_mask = pos + 1; |
|---|
| 82 | | pos = strchr(my_client_mask, '['); |
|---|
| 83 | | if (pos) |
|---|
| 84 | | { |
|---|
| 85 | | *pos = '\0'; |
|---|
| 86 | | } |
|---|
| 87 | | if (asprintf(&other_client, "%R", other_ts) < 0) |
|---|
| 88 | | { |
|---|
| 89 | | other_client = NULL; |
|---|
| 90 | | } |
|---|
| 91 | | pos = strchr(other_client, '/'); |
|---|
| 92 | | *pos = '\0'; |
|---|
| 93 | | other_client_mask = pos + 1; |
|---|
| 94 | | pos = strchr(other_client_mask, '['); |
|---|
| 95 | | if (pos) |
|---|
| 96 | | { |
|---|
| 97 | | *pos = '\0'; |
|---|
| 98 | | } |
|---|
| 99 | | |
|---|
| 100 | | if (vip) |
|---|
| 101 | | { |
|---|
| 102 | | if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0) |
|---|
| 103 | | { |
|---|
| 104 | | virtual_ip = NULL; |
|---|
| 105 | | } |
|---|
| 106 | | } |
|---|
| 107 | | else |
|---|
| 108 | | { |
|---|
| 109 | | if (asprintf(&virtual_ip, "") < 0) |
|---|
| 110 | | { |
|---|
| 111 | | virtual_ip = NULL; |
|---|
| 112 | | } |
|---|
| 113 | | } |
|---|
| 114 | | |
|---|
| 115 | | iface = charon->kernel_interface->get_interface( |
|---|
| 116 | | charon->kernel_interface, me); |
|---|
| 117 | | |
|---|
| 118 | | /* build the command with all env variables. |
|---|
| 119 | | * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing |
|---|
| 120 | | */ |
|---|
| 121 | | snprintf(command, sizeof(command), |
|---|
| 122 | | "2>&1 " |
|---|
| 123 | | "PLUTO_VERSION='1.1' " |
|---|
| 124 | | "PLUTO_VERB='%s%s%s' " |
|---|
| 125 | | "PLUTO_CONNECTION='%s' " |
|---|
| 126 | | "PLUTO_INTERFACE='%s' " |
|---|
| 127 | | "PLUTO_REQID='%u' " |
|---|
| 128 | | "PLUTO_ME='%H' " |
|---|
| 129 | | "PLUTO_MY_ID='%D' " |
|---|
| 130 | | "PLUTO_MY_CLIENT='%s/%s' " |
|---|
| 131 | | "PLUTO_MY_CLIENT_NET='%s' " |
|---|
| 132 | | "PLUTO_MY_CLIENT_MASK='%s' " |
|---|
| 133 | | "PLUTO_MY_PORT='%u' " |
|---|
| 134 | | "PLUTO_MY_PROTOCOL='%u' " |
|---|
| 135 | | "PLUTO_PEER='%H' " |
|---|
| 136 | | "PLUTO_PEER_ID='%D' " |
|---|
| 137 | | "PLUTO_PEER_CLIENT='%s/%s' " |
|---|
| 138 | | "PLUTO_PEER_CLIENT_NET='%s' " |
|---|
| 139 | | "PLUTO_PEER_CLIENT_MASK='%s' " |
|---|
| 140 | | "PLUTO_PEER_PORT='%u' " |
|---|
| 141 | | "PLUTO_PEER_PROTOCOL='%u' " |
|---|
| 142 | | "%s" |
|---|
| 143 | | "%s" |
|---|
| 144 | | "%s", |
|---|
| 145 | | up ? "up" : "down", |
|---|
| 146 | | my_ts->is_host(my_ts, me) ? "-host" : "-client", |
|---|
| 147 | | me->get_family(me) == AF_INET ? "" : "-v6", |
|---|
| 148 | | config->get_name(config), |
|---|
| 149 | | iface ? iface : "unknown", |
|---|
| 150 | | child_sa->get_reqid(child_sa), |
|---|
| 151 | | me, ike_sa->get_my_id(ike_sa), |
|---|
| 152 | | my_client, my_client_mask, |
|---|
| 153 | | my_client, my_client_mask, |
|---|
| 154 | | my_ts->get_from_port(my_ts), |
|---|
| 155 | | my_ts->get_protocol(my_ts), |
|---|
| 156 | | other, ike_sa->get_other_id(ike_sa), |
|---|
| 157 | | other_client, other_client_mask, |
|---|
| 158 | | other_client, other_client_mask, |
|---|
| 159 | | other_ts->get_from_port(other_ts), |
|---|
| 160 | | other_ts->get_protocol(other_ts), |
|---|
| 161 | | virtual_ip, |
|---|
| 162 | | config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "", |
|---|
| 163 | | script); |
|---|
| 164 | | free(my_client); |
|---|
| 165 | | free(other_client); |
|---|
| 166 | | free(virtual_ip); |
|---|
| 167 | | free(iface); |
|---|
| 168 | | |
|---|
| 169 | | DBG3(DBG_CHD, "running updown script: %s", command); |
|---|
| 170 | | shell = popen(command, "r"); |
|---|
| 171 | | |
|---|
| 172 | | if (shell == NULL) |
|---|
| 173 | | { |
|---|
| 174 | | DBG1(DBG_CHD, "could not execute updown script '%s'", script); |
|---|
| 175 | | return; |
|---|
| 176 | | } |
|---|
| 177 | | |
|---|
| 178 | | while (TRUE) |
|---|
| 179 | | { |
|---|
| 180 | | char resp[128]; |
|---|
| 181 | | |
|---|
| 182 | | if (fgets(resp, sizeof(resp), shell) == NULL) |
|---|
| 183 | | { |
|---|
| 184 | | if (ferror(shell)) |
|---|
| 185 | | { |
|---|
| 186 | | DBG1(DBG_CHD, "error reading output from updown script"); |
|---|
| 187 | | return; |
|---|
| 188 | | } |
|---|
| 189 | | else |
|---|
| 190 | | { |
|---|
| 191 | | break; |
|---|
| 192 | | } |
|---|
| 193 | | } |
|---|
| 194 | | else |
|---|
| 195 | | { |
|---|
| 196 | | char *e = resp + strlen(resp); |
|---|
| 197 | | if (e > resp && e[-1] == '\n') |
|---|
| 198 | | { /* trim trailing '\n' */ |
|---|
| 199 | | e[-1] = '\0'; |
|---|
| 200 | | } |
|---|
| 201 | | DBG1(DBG_CHD, "updown: %s", resp); |
|---|
| 202 | | } |
|---|
| 203 | | } |
|---|
| 204 | | pclose(shell); |
|---|
| 205 | | } |
|---|
| 206 | | enumerator->destroy(enumerator); |
|---|
| 207 | | } |
|---|
| 208 | | |
|---|
| 209 | | /** |
|---|
| 210 | | * Listener implementation |
|---|
| 211 | | */ |
|---|
| 212 | | static bool child_state_change(listener_t *this, ike_sa_t *ike_sa, |
|---|
| 213 | | child_sa_t *child_sa, child_sa_state_t state) |
|---|
| 214 | | { |
|---|
| 215 | | child_sa_state_t old; |
|---|
| 216 | | |
|---|
| 217 | | if (ike_sa) |
|---|
| 218 | | { |
|---|
| 219 | | old = child_sa->get_state(child_sa); |
|---|
| 220 | | |
|---|
| 221 | | if ((old == CHILD_INSTALLED && state != CHILD_REKEYING ) || |
|---|
| 222 | | (old == CHILD_DELETING && state == CHILD_DESTROYING)) |
|---|
| 223 | | { |
|---|
| 224 | | updown(ike_sa, child_sa, FALSE); |
|---|
| 225 | | } |
|---|
| 226 | | else if (state == CHILD_INSTALLED) |
|---|
| 227 | | { |
|---|
| 228 | | updown(ike_sa, child_sa, TRUE); |
|---|
| 229 | | } |
|---|
| 230 | | } |
|---|
| 231 | | return TRUE; |
|---|
| 232 | | } |
|---|