docs
[exim.git] / src / src / routers / ipliteral.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
9
10
11 #include "../exim.h"
12
13 #ifdef ROUTER_IPLITERAL         /* Remainder of file */
14 #include "rf_functions.h"
15 #include "ipliteral.h"
16
17
18 /* Options specific to the ipliteral router. Because some compilers do not like
19 empty declarations ("undefined" in the Standard) we put in a dummy value. */
20
21 optionlist ipliteral_router_options[] = {
22   { "", opt_hidden, {NULL} }
23 };
24
25 /* Size of the options list. An extern variable has to be used so that its
26 address can appear in the tables drtables.c. */
27
28 int ipliteral_router_options_count =
29   sizeof(ipliteral_router_options)/sizeof(optionlist);
30
31 /* Default private options block for the ipliteral router. Again, a dummy
32 value is present to keep some compilers happy. */
33
34 ipliteral_router_options_block ipliteral_router_option_defaults = { 0 };
35
36
37 #ifdef MACRO_PREDEF
38
39 /* Dummy entries */
40 void ipliteral_router_init(driver_instance *rblock) {}
41 int ipliteral_router_entry(router_instance *rblock, address_item *addr,
42   struct passwd *pw, int verify, address_item **addr_local,
43   address_item **addr_remote, address_item **addr_new,
44   address_item **addr_succeed) {return 0;}
45
46 #else   /*!MACRO_PREDEF*/
47
48
49 /*************************************************
50 *          Initialization entry point            *
51 *************************************************/
52
53 /* Called for each instance, after its options have been read, to enable
54 consistency checks to be done, or anything else that needs to be set up. */
55
56 void
57 ipliteral_router_init(driver_instance *rblock)
58 {
59 /*
60 ipliteral_router_options_block *ob =
61   (ipliteral_router_options_block *)(rblock->options_block);
62 */
63 }
64
65
66
67 /*************************************************
68 *              Main entry point                  *
69 *************************************************/
70
71 /* See local README for interface details. This router returns:
72
73 DECLINE
74   . the domain is not in the form of an IP literal
75
76 DEFER
77   . verifying the errors address caused a deferment or a big disaster such
78       as an expansion failure (rf_get_errors_address)
79   . expanding a headers_{add,remove} string caused a deferment or another
80       expansion error (rf_get_munge_headers)
81   . a problem in rf_get_transport: no transport when one is needed;
82       failed to expand dynamic transport; failed to find dynamic transport
83   . failure to expand or find a uid/gid (rf_get_ugid via rf_queue_add)
84   . self = "freeze", self = "defer"
85
86 PASS
87   . self = "pass"
88
89 REROUTED
90   . self = "reroute"
91
92 FAIL
93   . self = "fail"
94
95 OK
96   added address to addr_local or addr_remote, as appropriate for the
97   type of transport; this includes the self="send" case.
98 */
99
100 int
101 ipliteral_router_entry(
102   router_instance *rblock,        /* data for this instantiation */
103   address_item *addr,             /* address we are working on */
104   struct passwd *pw,              /* passwd entry after check_local_user */
105   int verify,                     /* v_none/v_recipient/v_sender/v_expn */
106   address_item **addr_local,      /* add it to this if it's local */
107   address_item **addr_remote,     /* add it to this if it's remote */
108   address_item **addr_new,        /* put new addresses on here */
109   address_item **addr_succeed)    /* put old address here on success */
110 {
111 /*
112 ipliteral_router_options_block *ob =
113   (ipliteral_router_options_block *)(rblock->options_block);
114 */
115 host_item *h;
116 const uschar *domain = addr->domain;
117 const uschar *ip;
118 int len = Ustrlen(domain);
119 int rc, ipv;
120
121 DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
122   rblock->drinst.name, addr->address, addr->domain);
123
124 /* Check that the domain is an IP address enclosed in square brackets. Remember
125 to allow for the "official" form of IPv6 addresses. If not, the router
126 declines. Otherwise route to the single IP address, setting the host name to
127 "(unnamed)". */
128
129 if (domain[0] != '[' || domain[len-1] != ']') return DECLINE;
130 ip = string_copyn(domain+1, len-2);
131 if (strncmpic(ip, US"IPV6:", 5) == 0 || strncmpic(ip, US"IPV4:", 5) == 0)
132   ip += 5;
133
134 ipv = string_is_ip_address(ip, NULL);
135 if (ipv == 0 || (disable_ipv6 && ipv == 6))
136   return DECLINE;
137
138 /* It seems unlikely that ignore_target_hosts will be used with this router,
139 but if it is set, it should probably work. */
140
141 if (verify_check_this_host(CUSS&rblock->ignore_target_hosts,
142         NULL, domain, ip, NULL) == OK)
143   {
144   DEBUG(D_route)
145       debug_printf("%s is in ignore_target_hosts\n", ip);
146   addr->message = US"IP literal host explicitly ignored";
147   return DECLINE;
148   }
149
150 /* Set up a host item */
151
152 h = store_get(sizeof(host_item), GET_UNTAINTED);
153
154 h->next = NULL;
155 h->address = string_copy(ip);
156 h->port = PORT_NONE;
157 h->name = domain;
158 h->mx = MX_NONE;
159 h->status = hstatus_unknown;
160 h->why = hwhy_unknown;
161 h->last_try = 0;
162
163 /* Determine whether the host is the local host, and if so, take action
164 according to the configuration. */
165
166 if (host_scan_for_local_hosts(h, &h, NULL) == HOST_FOUND_LOCAL)
167   {
168   int rc = rf_self_action(addr, h, rblock->self_code, rblock->self_rewrite,
169     rblock->self, addr_new);
170   if (rc != OK) return rc;
171   }
172
173 /* Address is routed to this host */
174
175 addr->host_list = h;
176
177 /* Set up the errors address, if any. */
178
179 rc = rf_get_errors_address(addr, rblock, verify, &addr->prop.errors_address);
180 if (rc != OK) return rc;
181
182 /* Set up the additional and removable headers for this address. */
183
184 rc = rf_get_munge_headers(addr, rblock, &addr->prop.extra_headers,
185   &addr->prop.remove_headers);
186 if (rc != OK) return rc;
187
188 /* Fill in the transport, queue the address for local or remote delivery, and
189 yield success. For local delivery, of course, the IP address won't be used. If
190 just verifying, there need not be a transport, in which case it doesn't matter
191 which queue we put the address on. This is all now handled by the route_queue()
192 function. */
193
194 if (!rf_get_transport(rblock->transport_name, &rblock->transport,
195       addr, rblock->drinst.name, NULL))
196   return DEFER;
197
198 addr->transport = rblock->transport;
199
200 return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
201   OK : DEFER;
202 }
203
204
205
206 # ifdef DYNLOOKUP
207 #  define ipliteral_router_info _router_info
208 # endif
209
210 router_info ipliteral_router_info =
211 {
212 .drinfo = {
213   .driver_name =        US"ipliteral",
214   .options =            ipliteral_router_options,
215   .options_count =      &ipliteral_router_options_count,
216   .options_block =      &ipliteral_router_option_defaults,
217   .options_len =        sizeof(ipliteral_router_options_block),
218   .init =               ipliteral_router_init,
219 # ifdef DYNLOOKUP
220   .dyn_magic =          ROUTER_MAGIC,           /*XXX*/
221 # endif
222   },
223 .code =                 ipliteral_router_entry,
224 .tidyup =               NULL,     /* no tidyup entry */
225 .ri_flags =             ri_yestransport
226 };
227
228 #endif  /*!MACRO_PREDEF*/
229 #endif  /*ROUTER_IPLITERAL*/
230 /* End of routers/ipliteral.c */